LINUXMAKER, OpenSource, Tutorials

Dynamic DNS (DDNS) on Debian Linux

By giving Internet providers first and foremost dynamic IP addresses that refresh every 24 hours, home computers can only be reached over the Internet if they know this dynamic IP address. This is quite cumbersome, especially if you want to use VPN lines to another computer on the Internet.

In order to be able to access the home PC or the home network via the Internet, they must therefore be reachable under a fixed Internet address. And here Dynamic DNS (DDNS) provides a technique for dynamically updating domains in a Domain Name System (DNS). This automatically and quickly changes the associated domain entry on the responsible DNS server for a computer after changing its IP address. So the computer is always reachable under the same domain name, even if the current IP address for the user is unknown as mentioned.

How to set up such a DDNS server on Linux, will be explained here.

Requirements

Prerequisite, however, is an already functioning DNS server with Bind9. Furthermore, we assume that an example.org zone already exists. Debian requires not only the deb package 'bind9' but also the packages 'bind9-host', 'bind9utils' and 'dnsutils'.

Create keys for authentication

With dnssec-keygen a key is created, with which one can later authenticate itself at the DNS server.

# dnssec-keygen -a hmac-md5 -b 256 -n host dyndns.example.org

To the used options of the program so much that the parameter -a defines the algorithm, -b determines the bit number of the key and -n indicates the key type. For the number of bits we use the highest possible number according to manpage and since we do not want to generate the whole zone, but only for a certain host the key, we take the parameter "HOST".

After generating in the current directory you will find the following two files:

# -rw------- 1 root root  82 Apr 10 10:48 Kdyndns.example.org.+163+46242.key
# -rw------- 1 root root 188 Apr 10 10:48 Kdyndns.example.org.+163+46242.private

The contents of both files look something like this and is encoded base64

Private-key-format: v1.3
Algorithm: 163 (HMAC_MD5)
Key: LMbhYz5nZbP1c6OWTEJJ9sMKDQCvPy3kUO4y2aa+9cI=
Bits: AAA=
Created: 20140410084801
Publish: 20140410084801
Activate: 20140410084801

and

dyndns.example.org. IN KEY 512 3 163 LMbhYz5nZbP1c6OWTEJJ9sMKDQCvPy3kUO4y2aa+9cI=

The private key will be needed later on the actual client behind the dynamic IP address.

Advanced configuration of Bind9

In order for the corresponding zone file to be changed on the name server, the prerequisites must be created. First, the authentication for the said zone must be generated. So we create a key file called 'dyndns.example.org-key.key'.

# awk '/Key/{ print "key foobar.example.org {\n algorithm HMAC-SHA256;\n secret \"", $2, "\";\n};"  }' Kdyndns.example.org.+163+46242.private | tee -a /etc/bind/named.keys

The file /etc/bind/named.keys should then have a similar content as here and can accommodate several key entries

key dyndns.example.org {
  algorithm hmac-md5;
  secret " LMbhYz5nZbP1c6OWTEJJ9sMKDQCvPy3kUO4y2aa+9cI= ";
};

After this file is read only by the user bind and needs write permissions on the directory /etc/bind, the following is necessary

# chmod 600 /etc/bind/named.keys
# chown -R bind.bind /etc/bind

Then, the authentication is made known before the zone definitions in /etc/bind/name.conf.local.

include "/etc/bind/named.keys";

Permissions for the A record in the zone file

The aim is to give the user 'bind' the permission to change the A-record in the zone file concerned. This is made possible by the 'update-policy' option in the respective zone definition. Concretely so

zone "example.org" {
  type master;
  file "/var/lib/bind/db.example.org";
  update-policy {
    grant dyndns.example.org name dyndns.example.org. A;
  };
};

It is important to note that the first parameter of 'grant' in the update policy is the filename of the just generated keyfile. This authenticates that the Kdyndns.example.org.+163+46242.key key is allowed to modify the A record of dyndns.example.org in this zone file.

It is important to note that the first parameter of 'grant' in the update policy is the key name as recorded in the newly created key file. This authenticates that the key Kdyndns.example.org is allowed to change the A record of dyndns.example.org in this zone file. Furthermore, it is very important that the hostname is with a single dot . concludes.

Finally, a restart of the Bind service is necessary, as well as the look in the log file, if everything runs correctly.

# systemctl restart bind9
# tail -f /var/log/bind.log

Automatic update of the DNS server

So far, the DNS server is ready to accept authenticated changes to the zone file. During the runtime of the server, this is done with 'nsupdate' and the previously created private key.

# nsupdate -k /etc/ssl/Kdyndns.example.org.+163+46242.private
> server ns.example.org
> zone example.org
> update delete dyndns.example.org
> update add dndns.example.org 18000 A 84.189.213.55
> send

Translated, this means "Add a new A record called 'dndns.example.org' to the netserver 'ns.example.org' in the zone 'example.org' after adding the old entry 'dyndns.example.org The associated TTL is 5 hours and the IP address is 84.189.213.55 ".

Automation of the update

With the help of the following script and a cronjob the process just described can be automated.

########################################################################
#
# ddns-update
# Updates dynamic DNS zone entries
#
########################################################################


KEYFILE="/etc/ssl/Kdyndns.example.org.+163+46242.private
NAMESERVER="ns.example.org"
ZONE="example.org"
HOSTNAME="dyndns.example.org"
TTL="300"

if [ -z "$1" ]
then
  IPADDR="`curl -s ifconfig.me`"
else
  IPADDR="$1"
fi

(
  echo "server $NAMESERVER"
  echo "zone $ZONE"
  echo "update delete $HOSTNAME"
  echo "update add $HOSTNAME $TTL A $IPADDR"
  echo "send"
) | nsupdate -k $KEYFILE

# EOF

When an IP address is passed to the script, it uses it. Otherwise, the IP address is taken, which is provided by the transmission of the web address "ifconfig.me".

On the client side

The 'ddns-update' script is usually placed under '/usr/local/bin/' and made executable. With the help of a cron job, for example, with an hourly update,

$ crontab -e
00 * * * * /usr/local/bin/ddns-update

it is ensured that the DNS server always knows about the current IP address.
This creates a binary zone file with the extension ".jnl" and about 15 minutes later the actual zone file is rewritten.