Compare commits
10 Commits
f663788138
...
fe6a2ec75f
| Author | SHA1 | Date | |
|---|---|---|---|
| fe6a2ec75f | |||
| 424148141c | |||
| 0bbad483db | |||
| baef00dddc | |||
| 885154d33c | |||
| fb75de8dcb | |||
| acf4bc9979 | |||
| 4e9ea3dd18 | |||
| 9cb9bf9e7a | |||
| a11b90b721 |
23
CHANGELOG
Normal file
23
CHANGELOG
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
CHANGELOG
|
||||||
|
=========
|
||||||
|
|
||||||
|
Version 1.1 Changes (2019-08-05):
|
||||||
|
* Enhancements:
|
||||||
|
* Added config file support and a sample config file
|
||||||
|
* Implemented secret for list operator, listing is now disabled by default
|
||||||
|
* Enhanced domain selection mechanism and made it configurable (@DNSDomain)
|
||||||
|
* Reduced CNAME lookups to when really needed
|
||||||
|
* Sanitized HTTP Error codes and made output consistent (provide HTTP
|
||||||
|
response with error when normal things go wrong) and Hid detailed error
|
||||||
|
information in debug info so that end users cannot see this
|
||||||
|
* Made address autodetect explicit for updates (no more implicit autodetect)
|
||||||
|
The behavior of the update command changed so that it would not just pick
|
||||||
|
the remote address if no ip parameter was provided. This now also supports
|
||||||
|
setting one automatically and one specifically.
|
||||||
|
|
||||||
|
* Fixes:
|
||||||
|
* Fixed issue with listing the domain without 'domain' parameter
|
||||||
|
* Fixed issue with splice on perl versions > 5.23
|
||||||
|
* Fixed handling of expiry & calculation of expiry period
|
||||||
|
* Suppress unsupported records so that DNSSEC (RRSIG records) are no issue
|
||||||
|
|
||||||
474
README.md
474
README.md
@@ -2,50 +2,64 @@ dyndns.pl
|
|||||||
=========
|
=========
|
||||||
|
|
||||||
Perl CGI-BIN script to handle Dynamic DNS updates through HTTP (e.g. from a
|
Perl CGI-BIN script to handle Dynamic DNS updates through HTTP (e.g. from a
|
||||||
router), updating DNS records through secure DNS update statements.
|
router), updating DNS records through secure DNS update statements to run your
|
||||||
|
own Dynamic DNS Service.
|
||||||
|
|
||||||
**Version 1.0**, latest version, documentation and bugtracker available on my
|
**Version 1.1**, latest version, documentation and bugtracker available on my
|
||||||
[GitLab instance](https://gitlab.lindenaar.net/scripts/dyndns)
|
[GitLab instance](https://gitlab.lindenaar.net/scripts/dyndns)
|
||||||
|
|
||||||
Copyright (c) 2013 - 2015 Frederik Lindenaar. free for distribution under the
|
Copyright (c) 2013 - 2019 Frederik Lindenaar. free for distribution under the
|
||||||
GNU License, see [below](#license)
|
GNU License, see [below](#license)
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
This script provides a simple interface to allow Dynamic DNS updates for DNS
|
`dyndns.pl` 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
|
zones through HTTP requests. It is intended for routers and (aDSL) modems to
|
||||||
IP address by simply opening a URL (this is supported by many modern devices)
|
register their IP address by simply opening a URL (this is supported by most
|
||||||
but can also be used by end-users (either directly by using a client). Please
|
modern devices) but can also be used by end-users (either directly by using a
|
||||||
bear in mind that this script suits my setup and still might have glitches, but
|
client). The script itself uses DNS' `nsupdate` calls to perform the update.
|
||||||
so far turned out to be a quite stable solution for my needs and I use it in a
|
With this script you can integrate devices not supporting `nsupdate` and
|
||||||
production setup. In case you have any comments / questions or issues, please
|
environments where the master DNS server is not publicly available. The script
|
||||||
raise them through my
|
suits my setup/and needs and still might have glitches, but turned out to be a
|
||||||
[GitLab instance](https://gitlab.lindenaar.net/scripts/dyndns) so that all
|
very stable solution the last 6 years on both Linux as well as MacOS.
|
||||||
users benefit.
|
|
||||||
|
|
||||||
Setup
|
Please [see below](#integration) on how to setup the client side including:
|
||||||
-----
|
* [Cisco Routers](#cisco_integration)
|
||||||
|
* [AVM Fritz!Box routers](#fritzbox_integration)
|
||||||
|
* [Synology DSM](#synology_integration) (NAS)
|
||||||
|
|
||||||
|
In case you have any comments / questions or issues, please raise them through
|
||||||
|
my [GitLab instance](https://gitlab.lindenaar.net/scripts/dyndns) so that other
|
||||||
|
users can benefit and respond. Please also use this to submit setup instructions
|
||||||
|
for other devices you have set up for inclusion in this document.
|
||||||
|
|
||||||
|
|
||||||
|
Setup of the server side
|
||||||
|
========================
|
||||||
This script is to be executed as CGI-BIN script by a web server. As it is
|
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
|
written in Perl, it requires that installed (which is pretty standard on \*nix
|
||||||
on all *nix platforms). This description covers the installation on Apache 2.4,
|
platforms). This description covers the installation on Apache 2.4 and should be
|
||||||
which should be similar for other web servers, with ISC Bind v9. For performance
|
similar for other web servers, with ISC Bind v9. For performance reasons
|
||||||
reasons consider using the Apache mod_perl module for highly a volatile domain.
|
consider using the Apache mod_perl module for highly a volatile domain.
|
||||||
|
|
||||||
|
|
||||||
|
<a name=installation>Installation</a>
|
||||||
|
-------------------------------------
|
||||||
The setup of this solution consists of the following steps:
|
The setup of this solution consists of the following steps:
|
||||||
|
|
||||||
1. Ensure that the Perl modules CGI and Net::DNS are installed.
|
1. Ensure that the Perl modules CGI and Net::DNS are installed.
|
||||||
* on Debian/Ubunto linux this can be done by:
|
* on Debian/Ubuntu linux this can be done with:
|
||||||
|
|
||||||
~~~~
|
~~~
|
||||||
sudo apt-get install libcgi-pm-perl libnet-dns-perl
|
sudo apt-get install libcgi-pm-perl libnet-dns-perl
|
||||||
~~~~
|
~~~
|
||||||
|
|
||||||
* or if you have cpan installed:
|
* or directly from CPAN (assuming that is installed):
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
cpan CGI Net::DNS
|
cpan CGI Net::DNS
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
2. Install the file `dyndns.pl` either in your cgi-bin directory or in a
|
2. Install the file `dyndns.pl` either in your cgi-bin directory or in a
|
||||||
separate folder
|
separate folder
|
||||||
@@ -60,7 +74,9 @@ The setup of this solution consists of the following steps:
|
|||||||
server's cgi-bin directory) add the following line to your Apache virtual
|
server's cgi-bin directory) add the following line to your Apache virtual
|
||||||
host configuration (replacing `[INSTALL_DIR]` with the install directory):
|
host configuration (replacing `[INSTALL_DIR]` with the install directory):
|
||||||
|
|
||||||
ScriptAlias /dyndns [INSTALL_DIR]/dyndns.pl
|
~~~
|
||||||
|
ScriptAlias /dyndns [INSTALL_DIR]/dyndns.pl
|
||||||
|
~~~
|
||||||
|
|
||||||
in case you have installed the script in a non-standard folder, you will
|
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
|
also need the following to make this work on Apache 2.4 (again replacing
|
||||||
@@ -75,7 +91,10 @@ The setup of this solution consists of the following steps:
|
|||||||
~~~
|
~~~
|
||||||
|
|
||||||
reload apache with `/etc/init.d/apache reload` to make the script
|
reload apache with `/etc/init.d/apache reload` to make the script
|
||||||
available at <http://myserver.mydomain.tld/dyndns>
|
available at <http://myserver.mydomain.tld/dyndns>.
|
||||||
|
|
||||||
|
It is also possible to run as a virtual host, [see below](#VirtualHost) for
|
||||||
|
an example of that.
|
||||||
|
|
||||||
5. To setup your Bind nameserver, either update `named.conf` direcly or create
|
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
|
a separate file (e.g. `named.dyndns.conf` in the Bind configuration
|
||||||
@@ -112,7 +131,7 @@ The setup of this solution consists of the following steps:
|
|||||||
two signer/keys. *siteuser* only can update `site.dyndns.mydomain.tld`
|
two signer/keys. *siteuser* only can update `site.dyndns.mydomain.tld`
|
||||||
while *dyndns.mydomain.tld* can update all entries in the domain (intended
|
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
|
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
|
list of all entries, uncomment the `allow-transfer` statement and update
|
||||||
the IP adres to that of your web server.
|
the IP adres to that of your web server.
|
||||||
|
|
||||||
To seed these entries with fresh keys), use the following
|
To seed these entries with fresh keys), use the following
|
||||||
@@ -136,7 +155,7 @@ The setup of this solution consists of the following steps:
|
|||||||
~~~
|
~~~
|
||||||
$TTL 3600 ; 1 hour
|
$TTL 3600 ; 1 hour
|
||||||
@ IN SOA auth.dns.mydomain.tld. hostmaster.mydomain.tld. (
|
@ IN SOA auth.dns.mydomain.tld. hostmaster.mydomain.tld. (
|
||||||
2015051401 ; serial
|
2019000001 ; serial
|
||||||
43200 ; refresh (12 hours)
|
43200 ; refresh (12 hours)
|
||||||
3600 ; retry (1 hour)
|
3600 ; retry (1 hour)
|
||||||
86400 ; expire (24 hours)
|
86400 ; expire (24 hours)
|
||||||
@@ -156,7 +175,6 @@ The setup of this solution consists of the following steps:
|
|||||||
the bind `nsupdate` command instead. If that is inconvenient, the following
|
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
|
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):
|
(please note that when you have views this works slightly differently):
|
||||||
|
|
||||||
* execute the command `rndc freeze [zone]`
|
* execute the command `rndc freeze [zone]`
|
||||||
* edit the zone file for [zone]
|
* edit the zone file for [zone]
|
||||||
* execute the command `rndc unfreeze [zone]`
|
* execute the command `rndc unfreeze [zone]`
|
||||||
@@ -165,41 +183,113 @@ The setup of this solution consists of the following steps:
|
|||||||
and test the setup. please see [below how to invoke the script](#invoking).
|
and test the setup. please see [below how to invoke the script](#invoking).
|
||||||
|
|
||||||
URLs / checks to perform are:
|
URLs / checks to perform are:
|
||||||
|
|
||||||
* <http://myserver.mydomain.tld/dyndns/list?domain=dyndns.mydomain.tld>
|
* <http://myserver.mydomain.tld/dyndns/list?domain=dyndns.mydomain.tld>
|
||||||
to list the entries in the domain (requires zone transfer rights!)
|
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=......>
|
* <http://myserver.mydomain.tld/dyndns/update?host=site.dyndns.mydomain.tld&user=siteuser&secret=......>
|
||||||
to add/update a site and
|
to add/update a site and
|
||||||
* <http://myserver.mydomain.tld/dyndns/delete?host=site.dyndns.mydomain.tld&user=siteuser&key=......>
|
* <http://myserver.mydomain.tld/dyndns/delete?host=site.dyndns.mydomain.tld&user=siteuser&secret=......>
|
||||||
to delete (clear) it.
|
to delete (clear) it.
|
||||||
|
|
||||||
Please read the section below as well on the configuration and different modes
|
Please read the section below as well on the configuration and different modes
|
||||||
(operations) available.
|
(operations) available.
|
||||||
|
|
||||||
|
|
||||||
<a name=configuration>Configuration</a>
|
<a name=configuration>Configuration</a>
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
At the top of the script is a "Configuration" section, which contains the
|
At the top of the script is a "Configuration" section, which contains the
|
||||||
configurable options of the scripts.
|
configurable options of the scripts. As of version 1.1 the script also supports
|
||||||
|
a [configuration file](#config_file) so that modifying the script is no longer
|
||||||
|
required.
|
||||||
|
|
||||||
|
|
||||||
Parameter | Description
|
Parameter | Description
|
||||||
:----------------+:-------------------------------------------------------------
|
:----------------|:-------------------------------------------------------------
|
||||||
|
`$ConfigFile` | Enable/disable config file support, [see below](config_file)
|
||||||
`$DNSServer` | IP address of the DNS Server to send DNS update requests to
|
`$DNSServer` | IP address of the DNS Server to send DNS update requests to
|
||||||
`$ExpandCNAMEs` | Max. CNAME lookups for `$host` (0 to disable), see below
|
`@DNSDomain` | How to determine the host's domain name, [see below](#conf_dnszone)
|
||||||
|
`$DomainListKey` | Secret required to use the list mode, set to '' to always enable and to 'off' to disable this mode
|
||||||
|
`$ExpandCNAMEs` | Max. CNAME lookups for `$host` (0 to disable), [see below](#conf_cname)
|
||||||
`$AllowDebugKey` | Output debug log after result when `debug` parameter equals this value. Set to '' to always enable and to 'off' to disable debugging
|
`$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
|
`$AuthMode` | Defines how to authenticate DNS update requests, [see below](#conf_auth)
|
||||||
`$StaticSigner` | Static signer ID to be used for AuthMode `static` or `both`
|
`$StaticSigner` | Static signer ID to be used for AuthMode `static` or `both`
|
||||||
`$StaticKey` | Static signing key 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.
|
`$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).
|
`$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.
|
`@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
|
`$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.
|
`$DeleteTXT` | Set TXT record upon deletion with this text and a timestamp.
|
||||||
|
`$RecordTTL` | TTL for created records in minutes, hours, weeks or seconds. Format is number optionally followed by m, h, w, s (seconds is default)
|
||||||
|
|
||||||
Please note that the values must be correctly quoted, etc. not to break the script.
|
Please note: when changing the script all values must be correctly quoted, etc.
|
||||||
|
not to break the script. Therefore as of version 1.1 a config file is supported
|
||||||
|
(preferred), [see below](config_file).
|
||||||
|
|
||||||
|
|
||||||
#### CNAME Support
|
#### <a name=config_file>Configuration File</a>
|
||||||
|
The script can read its settings from a config located in the same directory as
|
||||||
|
the script and with the extension `.cfg` (ignoring a `.pl` extension) so the
|
||||||
|
default config file would be `dyndns.cfg`. The behavior of how to support the
|
||||||
|
config file is configured through the variable `$ConfigFile` and can be one of:
|
||||||
|
* `optional` - config file is read if it exists, this is the default
|
||||||
|
* `required` - config file is read and must exist (or the script will fail)
|
||||||
|
* `ignore` - config file is ignored and not read, configuration in the script
|
||||||
|
|
||||||
|
The general format of the config file is `keyword = value`, see the table below
|
||||||
|
for a mapping of the parameters to keywords. For lists (variables starting with
|
||||||
|
a `@`) the value is comma-separated. The config file supports comments, ignores
|
||||||
|
empty lines, starting/trailing spaces and everything following a `#`. Refer to
|
||||||
|
`dyndns.cfg.dist` for an example config file. Please note that the script will
|
||||||
|
fail if it encounters an error or unknown keyword in the config file.
|
||||||
|
|
||||||
|
Parameter | Config Setting | Default value
|
||||||
|
:-----------------|:-------------------|:------------------------------
|
||||||
|
`$AllowDebugKey` | `allow_debug_key` | `off` (debugging disabled)
|
||||||
|
`$AuthMode` | `auth_mode` | `remote` ([see below](#conf_auth))
|
||||||
|
`$DeleteTXT` | `delete_txt` | `DynDNS cleared on`
|
||||||
|
`$DNSServer` | `dns_server` | `192.168.1.1`
|
||||||
|
`@DNSDomain` | `dns_domain` | `?, !, 0` ([see below](#conf_dnszone))
|
||||||
|
`$DomainListKey` | `domain_list_key` | `off` (domain list disabled)
|
||||||
|
`$ExpandCNAMEs` | `expand_cnames` | `1` (1 level, [see below](#conf_cname))
|
||||||
|
`$ExpireAfter` | `expire_after` | `1w` (1 week, [see below](#expire))
|
||||||
|
`$RecordTTL` | `record_ttl` | `1h` (1 hour)
|
||||||
|
`$RequireRR` | `require_rr` |
|
||||||
|
`@ReplaceRR` | `replace_rr` | `A, AAAA, TXT`
|
||||||
|
`$StaticKey` | `static_key` |
|
||||||
|
`$StaticSigner` | `static_signer` |
|
||||||
|
`$UpdateTXT` | `update_txt` | `Last DynDNS update on`
|
||||||
|
|
||||||
|
Please note that since `$ConfigFile` determines config file support, it cannot
|
||||||
|
be configured in the file. By default the config file is optional not to break
|
||||||
|
existing configurations.
|
||||||
|
|
||||||
|
|
||||||
|
#### <a name=conf_dnszone>DNS Zone (Domain Name) Selection</a>
|
||||||
|
In order to send the right update request to the DNS server, the correct DNS
|
||||||
|
zone to update must be determined based on the request's hostname. Most of the
|
||||||
|
time an update for `hostname.subdomain.mydomain.tld` is an update of `hostname`
|
||||||
|
the DNS zone `subdomain.mydomain.tld` and then the defaults are sufficient.
|
||||||
|
However, in some scenarios (e.g. one of my use cases) an update should be sent
|
||||||
|
for hostname `hostname.subdomain` in the zone `mydomain.tld` instead. The DNS
|
||||||
|
server cannot figure this out itself (at least ISC's Bind9 can not) so it is
|
||||||
|
implemented here.
|
||||||
|
|
||||||
|
The array `@DNSDomain` contains a list of values matched against the hostname
|
||||||
|
to determine the DNS zone to update and can contain:
|
||||||
|
|
||||||
|
Value | match hostname ending with
|
||||||
|
:----------------|:-------------------------------------------------------
|
||||||
|
`"?"` | the domain name from parameter `domain`
|
||||||
|
`"!"` | server name the HTTP(S) request was sent to
|
||||||
|
`0` | domain from hostname (strip of everythin till first `.`)
|
||||||
|
positive number | last # parts from hostname
|
||||||
|
negative number | last # parts of server name the HTTP(S) request was sent to
|
||||||
|
any other string | use value specified
|
||||||
|
|
||||||
|
The first parameter matching the hostname's end will be used. The default is
|
||||||
|
`( '?', '!', 0 )`, which should be OK in most cases.
|
||||||
|
|
||||||
|
|
||||||
|
#### <a name=conf_cname>CNAME Support</a>
|
||||||
The script supports using separate subdomain (e.g. dyndns.mydomain.tld) for
|
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.
|
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)
|
mydomain.tld). The advantage of such a setup is that only one zone (SOA file)
|
||||||
@@ -212,17 +302,18 @@ 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
|
hostname instead of the provided one. The value of `$ExpandCNAMEs` determines
|
||||||
the maximum number of CNAME lookups supported (so nesting is allowed and this
|
the maximum number of CNAME lookups supported (so nesting is allowed and this
|
||||||
limits the level of nesting to prevent loops).
|
limits the level of nesting to prevent loops).
|
||||||
|
|
||||||
To disable lookups for CNAME expansion, set `$ExpandCNAMEs` to 0.
|
To disable lookups for CNAME expansion, set `$ExpandCNAMEs` to 0.
|
||||||
|
|
||||||
|
|
||||||
#### Authentication Modes
|
#### <a name=conf_auth>Authentication Modes</a>
|
||||||
For signing DNS update requests sent to the DNS server the script supports 3
|
For signing DNS update requests sent to the DNS server the script supports 3
|
||||||
ways to obtain the signer and key:
|
ways to obtain the signer and key:
|
||||||
|
|
||||||
AuthMode | Description
|
AuthMode | Description
|
||||||
:--------+:---------------------------------------------------------------------
|
:--------|:---------------------------------------------------------------------
|
||||||
*static* | use only static authentication information from `$StaticSigner` and`$StaticKey` (and ignore authentication information provided in the request)
|
*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
|
*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
|
*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
|
||||||
|
|
||||||
|
|
||||||
@@ -230,51 +321,59 @@ Supported Operations
|
|||||||
--------------------
|
--------------------
|
||||||
The script can perform the following operations (modes):
|
The script can perform the following operations (modes):
|
||||||
|
|
||||||
Mode | Description | Required Parameters | Optional Parameters
|
Mode | Description | Required Parameters | Optional Parameters
|
||||||
:------+:-------------------------+:--------------------+:----------------------
|
:------|:-----------------------|:--------------------|:----------------------
|
||||||
list | Show DDNS domain entries | `domain`__**__ |
|
list | List zone __***__ | `secret` __***__ | `domain`__**__
|
||||||
view | Show DDNS hostname entry | `host` |
|
view | Show host's DNS entry | `host` |
|
||||||
update | Update/add a DDNS host | `host` + auth.__*__ | `ipv4addr`, `ipv6addr`
|
update | Update/add a DDNS host | `host` + auth.__*__ | `ipv4addr`, `ipv6addr`
|
||||||
delete | Remove DDNS registration | `host` + auth.__*__ |
|
delete | Remove registration | `host` + auth.__*__ |
|
||||||
expire | Expire registrations | `domain`__**__ + auth.__*__
|
expire | Expire registrations | `domain`__**__ + auth.__*__
|
||||||
|
|
||||||
__*__ Modes that change registrations require authentication, depending on the
|
__*__ modes that change DNS require authentication, depending on the value of
|
||||||
value of `$AuthMode` the parameters `user` and `secret` may be required
|
`$AuthMode` the parameters `user` and `secret` may be required
|
||||||
(`$AuthMode` *remote*) required or optional (`$AuthMode` *both*)
|
(`$AuthMode` *remote*) required or optional (`$AuthMode` *both*)
|
||||||
|
|
||||||
__**__ in case `domain` is omitted, it will be determined using the `host`
|
__**__ in case `domain` is omitted, it will be determined using the `host`
|
||||||
parameter, if provided
|
parameter, if provided, or by using the virtualhost the script runs on
|
||||||
|
based on the `@DNSDomain` setting
|
||||||
|
|
||||||
|
__***__ list mode is only available when `$DomainListKey` is not set to `off`,
|
||||||
|
in case `$DomainListKey` is not empty, `secret` is required and must
|
||||||
|
equal the key in `$DomainListKey`
|
||||||
|
|
||||||
|
|
||||||
#### Parameters
|
#### <a name=req_params>Request Parameters</a>
|
||||||
The script supports the following parameters (please see the table above for which is needed for what mode):
|
The script supports (requires) the following parameters (please see the table
|
||||||
|
above for which is needed for what mode):
|
||||||
|
|
||||||
Parameter | Description
|
Parameter | Description
|
||||||
:---------+:--------------------------------------------------------------------
|
:----------|:-------------------------------------------------------------------
|
||||||
`mode` | the action to perform (if not provided as part of the path name)
|
`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
|
`domain` | domain for list/expire request, determined from `host` if ommitted
|
||||||
`host` | hostname to act on, expand CNAMEs max. `$ExpandCNAMEs` levels deep
|
`host` | hostname to act on, expand CNAMEs max. `$ExpandCNAMEs` levels deep
|
||||||
`ip` | alias / shortcut for `ipv4addr`
|
`ip` | alias / shortcut for `ipv4addr`
|
||||||
`ipv4addr`| The IPv4 address to register for the host (update mode only) __*__
|
`ipv4addr` | The IPv4 address to register for the host (update mode only) __*__
|
||||||
`ipv6addr`| The IPv6 address to register for the host (update mode only) __*__
|
`ipv6` | alias / shortcut for `ipv6addr`
|
||||||
`user` | signer of the DNS Update, used for `AuthMode` *remote* and *both*
|
`ipv6addr` | The IPv6 address to register for the host (update mode only) __*__
|
||||||
`key` | key to sign the DNS Update, used for `AuthMode` *remote* and *both*
|
`user` | signer of the DNS Update, used for `AuthMode` *remote* and *both*
|
||||||
`debug` | debug key, show debug information if this equals `$AllowDebugKey`
|
`secret` | key to sign the DNS Update, used for `AuthMode` *remote* and *both*, also used as `$DomainListKey` for list mode.
|
||||||
|
`debug` | debug key, show debug information if this equals `$AllowDebugKey`
|
||||||
|
|
||||||
__*__ in update mode, if `ipv4addr` or `ipv6addr` is not provided with the
|
__*__ in update mode, if `ipv4addr` or `ipv6addr` is set to `auto` in the
|
||||||
request, the CGI variable `$REMOTE_ADDR` (the client address), its value
|
request, the CGI variable `$REMOTE_ADDR` (the client address), its value
|
||||||
will be used instead as IPv4/IPv6 address.
|
will be used instead as IPv4/IPv6 address. __Please Note__ that if both
|
||||||
|
are omitted existing addresses will be removed!
|
||||||
|
|
||||||
|
|
||||||
#### <a name="invoking">Invoking the script</a>
|
#### <a name=invoking>Invoking the script</a>
|
||||||
The script is implemented using the perl CGI module so for testing purposes it
|
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.
|
can be called from the command line with parameters as arguments, i.e.
|
||||||
|
|
||||||
./dyndns.pl mode=expire domain=mydomain.tld debug=....
|
./dyndns.pl mode=expire domain=mydomain.tld debug=....
|
||||||
|
|
||||||
Which is quite handy for debugging purposes. Please note that the Perl CGI
|
Which is quite handy for debugging. Please note that the Perl CGI library sets
|
||||||
library sets `$REMOTE_ADDR` to 127.0.0.1 and that the output will always be
|
`$REMOTE_ADDR` to 127.0.0.1, the server name in this case will be `localhost`
|
||||||
the HTML-based result.
|
and that the output is the HTML result.
|
||||||
|
|
||||||
The standard way to use the script is to place it in the cgi-bin folder your
|
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:
|
server, which allows it to be called as:
|
||||||
@@ -295,14 +394,54 @@ When combining the setup would become:
|
|||||||
|
|
||||||
http://myserver.mydomain.tld/dyndns/list?domain=mydomain.tld&debug=...
|
http://myserver.mydomain.tld/dyndns/list?domain=mydomain.tld&debug=...
|
||||||
|
|
||||||
|
If using a dedicated virtual host [see below](#VirtualHost) it becomes:
|
||||||
|
|
||||||
|
http://myserver.mydomain.tld/list?domain=mydomain.tld&debug=...
|
||||||
|
|
||||||
Which is how I use it.
|
Which is how I use it.
|
||||||
|
|
||||||
|
|
||||||
|
### <a name=expire>Expiring Records</a>
|
||||||
|
The script can expire registrations after a while. For this, it must add a TXT
|
||||||
|
record containing the date of the last change (on by default) and when requested
|
||||||
|
it will remove any entry older than the value configured in `$ExpireAfter`.
|
||||||
|
|
||||||
|
Please note that:
|
||||||
|
* as this is dependent on the value of a TXT record, it may fail if these
|
||||||
|
records are updated through another method.
|
||||||
|
* there is no security implemented (other than the value of `$ExpireAfter`)
|
||||||
|
|
||||||
|
To initiate the expiry, the script must be called with two parameters:
|
||||||
|
1. `mode` should be set to `expire`
|
||||||
|
2. `domain` must be set to the DNS Zone (domain) to run against.
|
||||||
|
|
||||||
|
Both can be setup easily in cron with entries like:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
# Samples to run the expiry every hour
|
||||||
|
|
||||||
|
# Cron fields definition:
|
||||||
|
#.---------------- minute (0 - 59)
|
||||||
|
#| .------------- hour (0 - 23)
|
||||||
|
#| | .---------- day of month (1 - 31)
|
||||||
|
#| | | .------- month (1 - 12) OR jan,feb,mar,apr ...
|
||||||
|
#| | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
|
||||||
|
#| | | | |
|
||||||
|
#* * * * * user-name command to be executed
|
||||||
|
|
||||||
|
# Directly run the script, does not require specific permissions
|
||||||
|
15 * * * * www-data [INSTALL_DIR]/dyndns.pl mode=expire domain=mydomain.tld
|
||||||
|
|
||||||
|
# example using curl
|
||||||
|
15 * * * * www-data curl https://myserver.mydomain.tld/expire?domain=mydomain.tld > /dev/null
|
||||||
|
~~~
|
||||||
|
|
||||||
|
|
||||||
Name Server Setup Requirements
|
Name Server Setup Requirements
|
||||||
------------------------------
|
------------------------------
|
||||||
As the script is only translating requests, depends heavily on the setup of the
|
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
|
nameserver. The DNS server (obviously) needs to allow DNS updates. In addition
|
||||||
to the setup described above, please note that:
|
to the setup described above, please note that:
|
||||||
|
|
||||||
* For the modes list and expire to work, the script needs to perform a DNS
|
* 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.
|
zone transfer (AXFR). This must be allowed for the host running the script.
|
||||||
@@ -314,22 +453,191 @@ to the setup described above, please note that:
|
|||||||
used Perl Net::DNS library). The keys setup in the nameservers must
|
used Perl Net::DNS library). The keys setup in the nameservers must
|
||||||
therefore be of the same time or authentication won't work.
|
therefore be of the same time or authentication won't work.
|
||||||
|
|
||||||
The solution scales reasonable well, although adding the keys to the nameserver
|
This setup has been tested against ISC Bind version 9 and scales pretty well.
|
||||||
configuration is still manual in my setup (but since it does not happen that
|
Adding the keys to the nameserver configuration is still manual in my setup but
|
||||||
often, it's no hassle). This setup has been tested against ISC Bind version 9.
|
bit difficult script, if needed.
|
||||||
|
|
||||||
|
|
||||||
<a name="license">License</a>
|
<a name=VirtualHost>Configure as Virtual Host</a>
|
||||||
-----------------------------
|
-------------------------------------------------
|
||||||
This script, documentation and configration examples are free software: you can
|
Running dyndns.pl on a Virtual Host is possible using `mod_rewrite`. This is how
|
||||||
|
I use it as it allows the URLs to become even more simple, e.g.:
|
||||||
|
|
||||||
|
* to update: `https://dyndns.mydomain.tld/update/hostname.mydomain.tld?secret=...`
|
||||||
|
* to delete: `https://dyndns.mydomain.tld/delete/hostname.mydomain.tld?secret=...`
|
||||||
|
* to view: `https://dyndns.mydomain.tld/view/hostname.mydomain.tld`
|
||||||
|
* to list: `https://dyndns.mydomain.tld/list/mydomain.tld?secret=...`
|
||||||
|
* to expire: `https://dyndns.mydomain.tld/expire/mydomain.tld`
|
||||||
|
|
||||||
|
An example Apache 2.4 config is shown below (please replace `[INSTALL_DIR]` with
|
||||||
|
the install directory and obviously replace the server name as well):
|
||||||
|
|
||||||
|
~~~
|
||||||
|
<VirtualHost *:80 *:443>
|
||||||
|
ServerName dyndns.mydomain.tld
|
||||||
|
|
||||||
|
# Enable URL Rewriting
|
||||||
|
RewriteEngine On
|
||||||
|
|
||||||
|
# Enforce HTTPS access
|
||||||
|
RewriteCond %{HTTPS} off
|
||||||
|
RewriteRule / https://%{HTTP_HOST}%{REQUEST_URI} [R]
|
||||||
|
|
||||||
|
# re-route everything to the dyndns script
|
||||||
|
RewriteRule (.*) /dyndns/$1 [PT]
|
||||||
|
|
||||||
|
ScriptAlias /dyndns [INSTALL_DIR]/dyndns.pl
|
||||||
|
|
||||||
|
<Directory [INSTALL_DIR]>
|
||||||
|
AllowOverride None
|
||||||
|
Options +ExecCGI -MultiViews
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
</VirtualHost>
|
||||||
|
~~~
|
||||||
|
|
||||||
|
|
||||||
|
<a name=integration>Integration with devices</a>
|
||||||
|
================================================
|
||||||
|
Integration on routers and other devices is straigtforward, provided do support
|
||||||
|
DDNS registrations using a custom URL. The Basic format for the registration
|
||||||
|
URL to register is:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
https://SERVER/cgi-bin/dyndns/update?host=HOSTNAME&ip=IPADDRESS&secret=KEY
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Check the [list of parameters supported](req_params) for all available options,
|
||||||
|
the above URL contains the absolute minimum where:
|
||||||
|
|
||||||
|
Parameter | Value
|
||||||
|
:-----------|:---------------------------------------------------------------
|
||||||
|
`SERVER` | is the host the script is installed on
|
||||||
|
`HOSTNAME` | is the client's hostname as configured in the DNS server
|
||||||
|
`SECRET` | is the secret key as configured in the DNS server
|
||||||
|
`IPADDRESS` | is the ipv4 address (often dynamic, can also be set to `auto`)
|
||||||
|
|
||||||
|
Depending on how you have configured the URL of the script to be, the path
|
||||||
|
(`/cgi-bin/dyndns/` may need to be altered as per your setup).
|
||||||
|
|
||||||
|
Please note that:
|
||||||
|
* The generated secret may contain a `+`, which must be encoded correctly in
|
||||||
|
the request or it will fail. I found that not all clients (e.g. a Fritz!Box)
|
||||||
|
do this correctly, make sure that your secrets either don't contain a `+`
|
||||||
|
or encode it manually (replace any `+` with `%2B` in that case).
|
||||||
|
* In case the IP address of the device is behind NAT and you want to have the
|
||||||
|
public address register, use the `auto` value for parameters `ip`/`ipv4addr`
|
||||||
|
and `ipv6`/`ipv6addr` to have the script auto-detect it (though that this
|
||||||
|
can only be used for either an IPv4 or an IPv6 address and will only work
|
||||||
|
for devices registering using that protocol!)
|
||||||
|
* Some devices have a preference to connect over IPv6 (e.g. Cisco routers).
|
||||||
|
This can be used to register the IPv4 and IPv6 addresses together by passing
|
||||||
|
the IPv4 address as parameter en setting the IPv6 parameter to `auto`.
|
||||||
|
* Some devices (e.g. a Fritz!Box) support a separate URL for IPv4 and IPv6
|
||||||
|
registrations. Unfortunately this script cannot handle this yet and will
|
||||||
|
unregister a previous registration when the second request comes in. Please
|
||||||
|
raise a ticket if you have such a situation to work on a solution together.
|
||||||
|
|
||||||
|
To check whether the client's registration was successful (and correct) visit:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
https://SERVER/cgi-bin/dyndns/view?host
|
||||||
|
~~~
|
||||||
|
|
||||||
|
|
||||||
|
<a name=cisco_integration>Cisco Routers</a>
|
||||||
|
-------------------------------------------
|
||||||
|
For Cisco routers add the following config:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
ip ddns update method DYNDNS
|
||||||
|
HTTP
|
||||||
|
add https://SERVER/cgi-bin/dyndns/update?host=<h>&ip=<a>&secret=SECRET
|
||||||
|
remove https://SERVER/cgi-bin/dyndns/delete?host=<h>&secret=SECRET
|
||||||
|
interval maximum 0 1 0 0
|
||||||
|
~~~
|
||||||
|
|
||||||
|
replacing `SERVER` for the host the script is installed on and `SECRET`
|
||||||
|
for a DNS key authorized to update the record. The cisco router will replace <a>
|
||||||
|
and <h> with the IPv4 address and hostname.
|
||||||
|
|
||||||
|
To setup interface `Dialer0` to register as `hostname.dyndns.mydomain.tld` add:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
interface Dialer0
|
||||||
|
ip ddns update hostname hostname.dyndns.mydomain.tld
|
||||||
|
ip ddns update DYNDNS
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Which instructs to register using the address of Dialer0 as soon as that is up
|
||||||
|
or changes (this also works for non-dialer devices).
|
||||||
|
|
||||||
|
Please note that before entering the `?` as part of the URL, a `CTRL`-`V` is
|
||||||
|
required to prevent the Cisco CLI to list the available command parameters.
|
||||||
|
|
||||||
|
|
||||||
|
<a name=fritzbox_integration>AVM Fritz!Box routers</a>
|
||||||
|
------------------------------------------------------
|
||||||
|
To setup DynDNS on a Fritz!Box perform the following steps:
|
||||||
|
* Login to your Fritz!Box as an admin user
|
||||||
|
* Open the 'Internet' menu an go through the 'External Access' page
|
||||||
|
* Open the 'DynDNS' tab
|
||||||
|
* Enable the 'Use DynDNS' checkbox
|
||||||
|
* Select DynDNS Provider: 'User-defined'
|
||||||
|
* Enter the following data (replacing `YOURDOMAIN` with your DynDNS domain
|
||||||
|
and `SERVER` with your server name - check the rest of the URL as well!)
|
||||||
|
- Update URL: `https://SERVER/cgi-bin/dyndns/update?host=<domain>&ip=<ipaddr>&secret=<pass>`
|
||||||
|
- Domain name: hostname setup in DNS
|
||||||
|
- Username/Email: put here something, not used unless you add it to the URL
|
||||||
|
- Password: secret key setup in DNS
|
||||||
|
* Click 'Apply' to store and activate the DDNS registrations
|
||||||
|
|
||||||
|
Check [this page](https://service.avm.de/help/en/FRITZ-Box-7581/017p2/hilfe_dyndns)
|
||||||
|
for the available parameters that can be substituted in the URL.
|
||||||
|
|
||||||
|
The status of the DynDNS registrations can be seen in the 'Internet' menu on the
|
||||||
|
'Online Monitor' page.
|
||||||
|
|
||||||
|
To stop DynDNS registrations, uncheck 'Use DynDNS' from the same screen.
|
||||||
|
|
||||||
|
|
||||||
|
<a name=synology_integration>Synology DSM (NAS)</a>
|
||||||
|
---------------------------------------------------
|
||||||
|
To setup DynDNS on a Synology NAS (DSM 6 or later) perform the following steps:
|
||||||
|
* Login to your Synology NAS DSM as an admin user
|
||||||
|
* Open the Control Panel and go to 'External Access'
|
||||||
|
* Click 'Customize' to add a new DDNS provider
|
||||||
|
* Enter the following data (replacing `YOURDOMAIN` with your DynDNS domain
|
||||||
|
and `SERVER` with your server name - check the rest of the URL as well!)
|
||||||
|
- Service Provider: `YOURDOMAIN`
|
||||||
|
- Query URL `https://SERVER/cgi-bin/dyndns/update?host=__HOSTNAME__&ip=__MYIP__&secret=__PASSWORD__`
|
||||||
|
* Click Save to store the custom DDNS provider
|
||||||
|
* Click Add to register the DDNS registration and enter:
|
||||||
|
- Service Provider: select the name you have just added (`*YOURDOMAIN`)
|
||||||
|
- Hostname: hostname setup in DNS
|
||||||
|
- Username/Email: put here something, not used unless you add it to the URL
|
||||||
|
- Password/Key: secret key setup in DNS
|
||||||
|
* Click 'OK' to store and activate the DDNS registrations
|
||||||
|
|
||||||
|
After a while the screen should display that the status is Normal and when the
|
||||||
|
last update occurred.
|
||||||
|
|
||||||
|
To stop DDNS registrations, 'Delete' the registration from the same screen.
|
||||||
|
|
||||||
|
|
||||||
|
<a name=license>License</a>
|
||||||
|
=============================
|
||||||
|
This script, documentation and configuration examples are free software: you can
|
||||||
redistribute and/or modify it under the terms of the GNU General Public License
|
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,
|
as published by the Free Software Foundation, either version 3 of the License,
|
||||||
or (at your option) any later version.
|
or (at your option) any later version.
|
||||||
|
|
||||||
This script, documenatation and configuration examples are distributed in the
|
This script, documentation and configuration examples are distributed in the
|
||||||
hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
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
|
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
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/>.
|
this program. If not, download it from <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
# DNS Settings
|
# DNS Settings
|
||||||
#dns_server = 192.168.1.1 # DNS Server to communicate with (use IP!)
|
#dns_server = 192.168.1.1 # DNS Server to communicate with (use IP!)
|
||||||
|
|
||||||
|
#dns_domain = ?, !, 1 # DNS Domain to support, match hostname with:
|
||||||
|
# '?': take domain name from parameter 'domain'
|
||||||
|
# '!': take domain name from virtualhost name
|
||||||
|
# 0: take domain from hostname
|
||||||
|
# positive number: last # parts from hostname
|
||||||
|
# negative number: last # parts from virtualhost
|
||||||
|
# any other string: use if hostname ends on it
|
||||||
|
|
||||||
#expand_cnames = 1 # CNAME levels to expand (0 to disable)
|
#expand_cnames = 1 # CNAME levels to expand (0 to disable)
|
||||||
#require_rr = # Require existing record of this type to update
|
#require_rr = # Require existing record of this type to update
|
||||||
#replace_rr = A, AAAA, TXT # Records types to replace (clear) during update
|
#replace_rr = A, AAAA, TXT # Records types to replace (clear) during update
|
||||||
@@ -18,6 +26,8 @@
|
|||||||
# hours, weeks or seconds. format: [0-9]+[mhws]?
|
# hours, weeks or seconds. format: [0-9]+[mhws]?
|
||||||
|
|
||||||
# Authentication Settings
|
# Authentication Settings
|
||||||
|
#domain_list_key = off # List operation, 'off' to disable, '' to always
|
||||||
|
# allow and other values to enable with secret
|
||||||
#auth_mode = remote # either 'static', 'remote' or 'both'
|
#auth_mode = remote # either 'static', 'remote' or 'both'
|
||||||
#static_signer = # required for AuthMode 'static' or 'both'
|
#static_signer = # required for AuthMode 'static' or 'both'
|
||||||
#static_key = # required for AuthMode 'static' or 'both'
|
#static_key = # required for AuthMode 'static' or 'both'
|
||||||
|
|||||||
64
dyndns.pl
64
dyndns.pl
@@ -31,9 +31,18 @@ my $ConfigFile = 'optional'; # hardcoded, either optional, required or ignore
|
|||||||
##############################
|
##############################
|
||||||
# Configuration section (defaults, can be set in config file)
|
# Configuration section (defaults, can be set in config file)
|
||||||
my $DNSServer = '192.168.1.1'; # DNS Server to communicate with (use IP!)
|
my $DNSServer = '192.168.1.1'; # DNS Server to communicate with (use IP!)
|
||||||
|
my @DNSDomain = ( '?', '!', 0 ); # DNS Domain to support, match hostname with:
|
||||||
|
# '?': take domain name from parameter 'domain'
|
||||||
|
# '!': take domain name from virtualhost name
|
||||||
|
# 0: take domain from hostname
|
||||||
|
# positive number: last # parts from hostname
|
||||||
|
# negative number: last # parts from virtualhost
|
||||||
|
# any other string: use if hostname ends on it
|
||||||
my $ExpandCNAMEs = 1; # CNAME levels to expand (0 to disable)
|
my $ExpandCNAMEs = 1; # CNAME levels to expand (0 to disable)
|
||||||
my $AllowDebugKey = 'off'; # Debuging, 'off' to disable, '' for always on
|
my $AllowDebugKey = 'off'; # Debuging, 'off' to disable, '' for always on
|
||||||
# and other values to enable with debug= param.
|
# and other values to enable with debug= param.
|
||||||
|
my $DomainListKey = 'off'; # List operation, 'off' to disable, '' to always
|
||||||
|
# allow and other values to enable with secret
|
||||||
my $AuthMode = 'remote'; # either 'static', 'remote' or 'both'
|
my $AuthMode = 'remote'; # either 'static', 'remote' or 'both'
|
||||||
my $StaticSigner = ''; # required for AuthMode 'static' or 'both'
|
my $StaticSigner = ''; # required for AuthMode 'static' or 'both'
|
||||||
my $StaticKey = ''; # required for AuthMode 'static' or 'both'
|
my $StaticKey = ''; # required for AuthMode 'static' or 'both'
|
||||||
@@ -63,8 +72,8 @@ sub periodSeconds($) {
|
|||||||
my ($number, $units) = ($_[0]=~/^(\d+)([smhdw])?$/);
|
my ($number, $units) = ($_[0]=~/^(\d+)([smhdw])?$/);
|
||||||
if($number && $units && $units cmp 's') {
|
if($number && $units && $units cmp 's') {
|
||||||
$number *= ($units eq 'm') ? 60 # Seconds per minute
|
$number *= ($units eq 'm') ? 60 # Seconds per minute
|
||||||
: ($units cmp 'h') ? 3600 # Seconds per hour
|
: ($units eq 'h') ? 3600 # Seconds per hour
|
||||||
: ($units cmp 'd') ? 86400 # Seconds per day
|
: ($units eq 'd') ? 86400 # Seconds per day
|
||||||
: 604800; # Seconds per week
|
: 604800; # Seconds per week
|
||||||
}
|
}
|
||||||
return $number;
|
return $number;
|
||||||
@@ -126,7 +135,6 @@ my $CE = 'Configuration Error';
|
|||||||
my $PE = 'Required parameter missing';
|
my $PE = 'Required parameter missing';
|
||||||
sub fail($$;$) {
|
sub fail($$;$) {
|
||||||
my ($errormsg, $debugmsg, $exitcode) = @_;
|
my ($errormsg, $debugmsg, $exitcode) = @_;
|
||||||
print $debug . "\n";
|
|
||||||
print $cgi->header(-status=>$exitcode || 503, -type=>'text/plain'),
|
print $cgi->header(-status=>$exitcode || 503, -type=>'text/plain'),
|
||||||
"ERROR - $errormsg" . ($debug ? ": $debugmsg\n" : "\n");
|
"ERROR - $errormsg" . ($debug ? ": $debugmsg\n" : "\n");
|
||||||
exit 0;
|
exit 0;
|
||||||
@@ -222,8 +230,9 @@ sub DNS_Update($$$$$$$) {
|
|||||||
|
|
||||||
##############################
|
##############################
|
||||||
# Handlers for the different requests
|
# Handlers for the different requests
|
||||||
sub handle_update($$$$$) {
|
sub handle_update($$$$) {
|
||||||
my ($mode, $host, $dnshost, $dnsdomain, $debug) = @_;
|
my ($mode, $host, $dnsdomain, $debug) = @_;
|
||||||
|
my $dnshost = expand_CNAME($host);
|
||||||
my ($signer, $key) = get_authinfo($cgi, $host);
|
my ($signer, $key) = get_authinfo($cgi, $host);
|
||||||
|
|
||||||
# perform the action
|
# perform the action
|
||||||
@@ -251,8 +260,8 @@ sub handle_update($$$$$) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub handle_expire($$$$$) {
|
sub handle_expire($$$$) {
|
||||||
my ($mode, $host, $dnshost, $dnsdomain, $debug) = @_;
|
my ($mode, $host, $dnsdomain, $debug) = @_;
|
||||||
my ($signer, $key) = get_authinfo($cgi, $host);
|
my ($signer, $key) = get_authinfo($cgi, $host);
|
||||||
|
|
||||||
my $debugmsg = ($debug) ? "\n" : '';
|
my $debugmsg = ($debug) ? "\n" : '';
|
||||||
@@ -269,7 +278,7 @@ sub handle_expire($$$$$) {
|
|||||||
if($rr->type eq 'TXT' &&
|
if($rr->type eq 'TXT' &&
|
||||||
$rr->txtdata=~/$UpdateTXT(.*\d\d:\d\d:\d\d \d{4})$/){
|
$rr->txtdata=~/$UpdateTXT(.*\d\d:\d\d:\d\d \d{4})$/){
|
||||||
if(my $lastupdate = parse_localtime($1)) {
|
if(my $lastupdate = parse_localtime($1)) {
|
||||||
DNS_Update($dnsdomain, $dnshost, undef, undef, $signer, $key, $debug)
|
DNS_Update($dnsdomain, $rr->name, undef, undef, $signer, $key, $debug)
|
||||||
unless($lastupdate > $validafter);
|
unless($lastupdate > $validafter);
|
||||||
if($debug) {
|
if($debug) {
|
||||||
$debugmsg .= ($lastupdate > $validafter) ? 'Keeping ' : 'Expiring ';
|
$debugmsg .= ($lastupdate > $validafter) ? 'Keeping ' : 'Expiring ';
|
||||||
@@ -286,8 +295,9 @@ sub handle_expire($$$$$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub handle_view($$$$$) {
|
sub handle_view($$$$) {
|
||||||
my ($mode, $host, $dnshost, $dnsdomain, $debug) = @_;
|
my ($mode, $host, $dnsdomain, $debug) = @_;
|
||||||
|
my $dnshost = expand_CNAME($host);
|
||||||
my $title = "DynDNS Updater - $host";
|
my $title = "DynDNS Updater - $host";
|
||||||
print $cgi->header(-status=>200),
|
print $cgi->header(-status=>200),
|
||||||
$cgi->start_html(-title => $title),
|
$cgi->start_html(-title => $title),
|
||||||
@@ -310,10 +320,14 @@ sub handle_view($$$$$) {
|
|||||||
print $cgi->end_html();
|
print $cgi->end_html();
|
||||||
}
|
}
|
||||||
|
|
||||||
sub handle_list($$$$$) {
|
sub handle_list($$$$) {
|
||||||
my ($mode, $host, $dnshost, $dnsdomain, $debug) = @_;
|
my ($mode, $host, $dnsdomain, $debug) = @_;
|
||||||
my $title = "DynDNS Updater - $dnsdomain";
|
my $title = "DynDNS Updater - $dnsdomain";
|
||||||
|
|
||||||
|
fail("Operation not allowed", ($DomainListKey eq 'off') ? "List is disabled"
|
||||||
|
: "No/incorrect authentication information provided", 403)
|
||||||
|
if ($DomainListKey eq 'off') || (($DomainListKey cmp '') && ($DomainListKey cmp $cgi->param('secret')));
|
||||||
|
|
||||||
print $cgi->header(-status=>200),
|
print $cgi->header(-status=>200),
|
||||||
$cgi->start_html(-title => $title),
|
$cgi->start_html(-title => $title),
|
||||||
$cgi->h1($title);
|
$cgi->h1($title);
|
||||||
@@ -345,7 +359,8 @@ if ($ConfigFile cmp 'ignore') {
|
|||||||
$CFGFile =~ s/(\.pl)?$/.cfg/;
|
$CFGFile =~ s/(\.pl)?$/.cfg/;
|
||||||
if (open (CONFIG, $CFGFile)) {
|
if (open (CONFIG, $CFGFile)) {
|
||||||
my %CONFIG = (
|
my %CONFIG = (
|
||||||
allow_debug_key => \$AllowDebugKey, dns_server => \$DNSServer,
|
allow_debug_key => \$AllowDebugKey, domain_list_key => \$DomainListKey,
|
||||||
|
dns_server => \$DNSServer, dns_domain => \@DNSDomain,
|
||||||
expand_cnames => \$ExpandCNAMEs, auth_mode => \$AuthMode,
|
expand_cnames => \$ExpandCNAMEs, auth_mode => \$AuthMode,
|
||||||
static_signer => \$StaticSigner, static_key => \$StaticKey,
|
static_signer => \$StaticSigner, static_key => \$StaticKey,
|
||||||
require_rr => \$RequireRR, replace_rr => \@ReplaceRR,
|
require_rr => \$RequireRR, replace_rr => \@ReplaceRR,
|
||||||
@@ -399,6 +414,20 @@ foreach my $rrtype (@ReplaceRR) {
|
|||||||
my $mode = $cgi->path_info || $cgi->param('mode') || 'view';
|
my $mode = $cgi->path_info || $cgi->param('mode') || 'view';
|
||||||
$mode=~s/^\/([^\/]+)(\/(.*))?/$1/;
|
$mode=~s/^\/([^\/]+)(\/(.*))?/$1/;
|
||||||
my $host = $cgi->param('host') || $3;
|
my $host = $cgi->param('host') || $3;
|
||||||
|
my $dnsdomain;
|
||||||
|
foreach my $d (@DNSDomain) {
|
||||||
|
if ($d eq '!') { $d = $cgi->virtual_host; }
|
||||||
|
elsif ($d eq '?') { $d = $cgi->param('domain'); }
|
||||||
|
elsif ($d =~ /-?\d+/) {
|
||||||
|
if ($d <0) { $d = join('.', splice(@{[ split(/\./, $cgi->virtual_host) ]}, $d)); }
|
||||||
|
else { $d = join('.', splice(@{[ split(/\./, $host) ]}, ($d) ? -$d : 1)); }
|
||||||
|
}
|
||||||
|
$dnsdomain = $d if (!$host || length($host) == length($d)+rindex($host,$d));
|
||||||
|
last if $dnsdomain;
|
||||||
|
}
|
||||||
|
fail($PE, "No host name to act on specified", 400)
|
||||||
|
unless $host || $mode eq 'list' || $mode eq 'expire';
|
||||||
|
fail($PE, "No host or domain name to act on specified", 400) unless $dnsdomain;
|
||||||
|
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
@@ -410,13 +439,8 @@ my %handlers = (
|
|||||||
list => \&handle_list,
|
list => \&handle_list,
|
||||||
expire => \&handle_expire,
|
expire => \&handle_expire,
|
||||||
);
|
);
|
||||||
if($host eq '' and $mode cmp 'list' and $mode cmp 'expire') {
|
if(my $handler = $handlers{$mode}) {
|
||||||
fail($PE, "No host name to act on specified", 400);
|
$handler->($mode, $host, $dnsdomain, $debug);
|
||||||
} elsif(my $handler = $handlers{$mode}) {
|
|
||||||
# Replace provided host with that of a CNAME it points to and determine domain
|
|
||||||
my $dnshost = ($host) ? expand_CNAME($host) : undef;
|
|
||||||
my $dnsdomain = $cgi->param('domain') || ($dnshost=~/\.(.*)$/)[0];
|
|
||||||
$handler->($mode, $host, $dnshost, $dnsdomain, $debug);
|
|
||||||
} else {
|
} else {
|
||||||
fail("File Not Found", "Invalid Mode '$mode' specified", 404);
|
fail("File Not Found", "Invalid Mode '$mode' specified", 404);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user