DNS Overview

DNS is a UDP (optionally TCP) based client/server protocol using port 53 on server side. There are mainly four
[There is also the now obsolete Invers Query, a Status message type, and the quite new DSO (DNS stateful operations) opcode]
DNS-protocol messages types, each of it related to a dedicated application.

  1. DNS Queries (recursive / non-recursive)

  2. Zone transfer, full or incremental

  3. Notify (A SOA query like DNS message)

  4. DNS updates (Usually authenticated)

There are three different types of DNS name server:

  1. Authoritative name server (ANS)
    These are the name servers hosting the content of a DNS domain (zone)

  2. Recursive name server (RNS), also called Resolver
    These are used in the query process only

  3. Forwarding name server (mostly useless but widespread today)
    Out of scope here.

Queries

  • The DNS query is the most used DNS message.

  • UDP as transport protocol but also TCP is used, especially if the response packet is larger than the maximum DNS UDP packet size (512 minimum, now adjustable)

  • Two query types:

    • recursive

    • iterative (non-recursive)

  • Queries are send by

    • Stub resolvers (clients) as recursive query against recursive name server (RNS)

    • Resolver (RNS) as non-recursive query against authoritative name servers (ANS)

queries.svg
Stub Resolver query (recursive) against recursive ns
$ dig  host.hznet.de @rns.hkn.hznet.de | grep -e "^host" -e ";; flags"

;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
host.hznet.de.          20776   IN      AAAA    2a01:4f8:150:92a9::2

The flags field in the message header shows that this is a query response (qr) with recursion desired (rd) and recursion available (ra) flag on. DNSSEC validation was successfull (ad). dig(1) sets the rd bit by default.

Resolver query (non-recursive) against the authoritative ns for the zone
$ dig  +norec host.hznet.de @ns1.hznet.de | grep -e "^host" -e ";; flags"

;; flags: qr aa ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
host.hznet.de.          21600   IN      AAAA    2a01:4f8:150:92a9::2

Here the rd bit is cleared and the aa bit (authoritative answer) is set.

Resolver query (non-recursive) against a ANS not responsible for the zone
$ dig  +norec host.hznet.de @a.nic.de | sed -n -e '/;; flags/p' -e '/^;; AUTH/,/^$/p'
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 3, ADDITIONAL: 5
;; AUTHORITY SECTION:
hznet.de.               86400   IN      NS      ns2.hznet.de.
hznet.de.               86400   IN      NS      ns1.hznet.de.
hznet.de.               86400   IN      NS      ns-ext.nlnetlabs.nl.

Because this name server is not authoritative for the domain in question, the response has no answer (ANSWER: 0) but an authority section. The authority section contains the full qualified domain names (FQDN) of all authoritative name servers for the domain in question.
That’s the best information the de. servers are aware of and is called a delegation. In the additional section (not shown here) the IP addresses of the name servers are provided as long as space in the UDP packet is available.

Zone Transfer

One authoritative name server per domain is not enough. A second or third or even more name servers are usually configured as authoritative name servers (ANS) for a domain.
But only one of them manages the source file for the zone.

  • This one is called the “primary” ANS.

  • All other NS are named “secondary” ANS.
    [Formaly those were called “Master” and “Slave” server, but this is rather a racism term.]

How is the content of a zone synchronized between the authoritative name servers of a zone?

zone-transfer.svg
AXFR

To replicate the zone database (a plain text file) to all secondary NS, the second DNS-protocol message format is used: A zone transfer (AXFR).

A zone transfer uses TCP as transport protocol and is initiated by each secondary NS at regular intervals (refresh time). It starts always with a SOA serial number comparison.

The SOA serial number is an integer within the header of a zone used for versioning of the zone.

Example 1. A SOA Record
$ dig +noall +answer SOA +multi hkn.hznet.de
hkn.hznet.de.           6012 IN SOA ns1.hznet.de. hostmaster.hznet.de. (
                               2021051803 ; serial
                               43200      ; refresh (12 hours)
                               1800       ; retry (30 minutes)
                               1209600    ; expire (2 weeks)
                               900        ; minimum (15 minutes)
                               )

Whenever a change on the primary NS is made on a zone file, the serial number MUST be incremented. A zone transfer to a secondary NS takes place only if the serial number on the primary is higher than the one on the secondary NS.
[This is the most common mistake done by dns admins: Forget to increment the serial number after a change in a zone]

NOTIFY

To speed up the transfer of a zone to the secondaries, the DNS protocol is supplemented by NOTIFY messages (RFC1996) to tell a secondary NS that something has changed on the primary.

A Notify message is a bit like a SOA query for a zone, except that the DNS opcode is NOTIFY and that it is send by the authoritative primary server to all secondary servers. The secondary response to the NOTIFY “query” with a response to signal that it is informed about the change.

The secondary NS initiate than a zone transfer in the same way as the timely triggered zone transfer.

IXFR

A second improvement made to the DNS protocol is a partial, so called “incremental” zone transfer (IXFR).

With IXFR only that part of a zone is transfered to the secondary which has changed between the zone version on the secondary and the one on the primary. The primary holds a journal file to know what has been changed which each version of the zone.

All this is needed to speed up the distribution of a zone change to all authoritative name servers, and helps the third kind of DNS protocol messages.

Updates

  • Dynamic Update (RFC2136) is a mechanism to change the content of a zone via DNS messages.

  • The destination of a DNS update message is always one of the authorititative NS (usually the master NS) of a zone.

  • Dynamic updates use UDP or TCP as transport protocol The DNS messages opcode is 5 (UPDATE).

  • These messages should use some kind of authentication (RFC3007).

    • Shared Secrets (TSIG HMAC or GSS-TSIG)

    • Public Keys (SIG0)

dyn-upd.svg

Policy

On the primary server, the zone is configured as dynamic zone and a update-policy directive defines who is allowed to update what kind of resource.

Example 2. BIND Update policy
 zone "example.net" {
     type master;   file "example.net.dyn";
     max-zone-ttl 43200;                        1
     serial-update-method date;                 2
     update-policy {
         //   identity ruletype name types
         grant ddns-key zonesub      ANY ;                      3
         grant EX.NET   krb5-self .  A(1) AAAA(3) TXT(2) SSHFP(10) HIP(2) KEY(2) IPSECKEY(2);   4
         grant *        self      .  A(1) AAAA(3) TXT(2) SSHFP(10) HIP(2) KEY(2) IPSECKEY(2);   5
     };
}
1 The maximum TTL value of the zone
2 Format of the SOA serial number, in this case: yyyymmddnn e.g. 2021052500
3 The owner of the key "local-ddns" can change any record in the zone and all sub zones
4 Each Kerberos host principal of the realm "EX.NET" can add/del/modify the address, txt and several key resource records
5 The same as above for TSIG HMAC and SIG0 keys

Beside a grant permission also a deny configuration is possible to restrict a more general grant.

The self, krb-self and ms-self rules are almost identical and are used to authenticate hosts via it’s TSIG or SIG0 keyname, via it’s Kerberos host principal (host/fqdn@REALM) or via the Windows machine name (fqdn$@REALM).

If the ruletype in the grant directive above is changed from self (or krb5-self) to selfsub (or krb5-selfsub respectively) than the identiy can also add subdomains of it’s name (e.g. host.example.net can also add an address or key for a name like int1.host.example.net).

The zonesub directive allows the owner of the key with the name local-ddns to change anything in the zone.

The resource records are there to restrict the grant to specific record types. An number in parenthesis restricts the number of records of this type.

Authentication

DNS data is typically public accessible. So everyone can send a query to an authoritative DNS server. If this is not intended the name server itself should not be reacheable. However, if the data is public, typically no authentication is needed for DNS queries.

This is not necessarily the case for zone transfers. Here often the transfer of the whole data of the zone is restricted to a small number of hosts, mainly to the secondary servers.
To achieve this, formerly ip access list where used, but nowadays the authorized server have to authenticates itself via TSIG shared keys.

If we take a look at DNS updates, the situation is completely different. By default no one should be able to change the data within a zone. This is only allowed to entities which are able to authenticate itself. A policy says what changes are allowed for which entity.

DNS uses three different authentication mechanism

  1. Shared secrets (TSIG) as already used for zone transfers

  2. Asymmetric keys (SIG0) or

  3. third party authentication like Unix Kerberos or Windows Active Directory

The shared secret method requires the exchange of the key via a secure channel and a configuration of the key on the primary name server and the client as well. The key is defined within the named.conf file with a key directive.

Example 3. BIND key specification
 key "ddns-key" {
        algorithm hmac-sha256;
        secret "DwyeTCqKBHlSrkuTVphG9cfr8hMvzlDA8q8nPNQB0AE=";
};

A copy of this is placed in a file on the system from which nsupdate will be run. The command ddns-confgen can be used to generate a hmac-sha256 key like the example above.

In case of asymmetric key authentication the key material could be generated with the dnssec-keygen command.

$ dnssec-keygen -n HOST -T KEY -a RSASHA256 -b 2048 host.example.net
Generating key pair......................+++++
................................................................+++++
Khost.example.net.+008+00566

$ ls -l Khost.example.net.+008+00566.*
-rw-rw-r-- 1 hoz hoz  389 Mai 25 18:49 Khost.example.net.+008+00566.key
-rw------- 1 hoz hoz 1776 Mai 25 18:49
Khost.example.net.+008+00566.private

$ cat Khost.example.net.+008+00566.key
host.example.net. IN KEY 512 3 8 AwEAAd5Oq0T/sOGAc.......ln2bX7tRnlE=

The outcome of the dnssec-keygen command is the public part of the key, stored in the file with the extension .key and the private key placed in the file with extension .private.

The public part of the key is written as a KEY resource record and must be placed into the zone in question.
The nsupdate client needs access to the private key file and uses this to authenticate itself.

Kerberos, and so Windows Active Directory as well, is a third party authentication system. All hosts and services are added with a key to the Kerberos Key Distribution Center (KDC). The primary name server needs a service principal like DNS/fqdn@REALM and every host needs a host principal host/fqdn@REALM within the kerberos realm.
The authentication takes place at the Key Distribution Center, and the primary DNS server has to check the policy only.

Updates

To send an update to a primary nameserver the tool nsupdate, which is part of the BIND software distribution, is used. It reads from stdin the records to be updated. Each line with a resource record starts with the word add or delete. A newline or a line with the word send sends the update to the primary authoritative name server of the zone.

$ {
>       echo "add host.example.net  7200 IN AAAA 2001:db8:10::5"
>       echo "send"
> } nsupdate -k <keyfile>

The <keyfile< is the name of file withe the shared secret or the private part of an asymmetric (SIG0) keyfile.

For Kerberos authentication the option -g of nsupdate is used (take a look at the ddnsupd script for a more detailed explanation how gss authentication works).

There are a lot more nsupdate commands available, but for adding or deleting an IP address this is almost all what is needed.
If the nsupdate(1) programm has difficulties to find the primary authoritative server of a domain, than the server command is useful. Also setting a default ttl with e.g. ttl 18000 can be helpful if the record doesn’t have a ttl value.

For a more detail explanation take a look at the man page of nsupdate(1).

Example

A real live example setup.

  1. Install the BIND software
    This is needed because the nsupdate (and dig) command is part of the BIND distribution. Some Unix/Linux distros may have a separate DNS “client” package, e.g. bind9-dnsutils.
    This is sufficient on the dynamic dns clients where the ddnsupd script runs.

  2. Setup a BIND authoritative name server
    There are a lot of HowTo’s in the internet explaining the setup of BIND

  3. Configure a domain for dynamic updates and reconfig your name server.
    Here it is shown with the domain mip6.de.

    # part of named.conf
    zone "mip6.de." in {
            type master;
            file "mip6.de.ddb";
            allow-transfer { <your-secondary-server-list-acl>; };
            max-zone-ttl 18000;             // max ttl is 5h
            serial-update-method unixtime;  // this is good for dynamic zones
            update-policy {
                    grant <your-master-hmac-key-name> zonesub ANY ;
                    grant * self .  A(0) AAAA(3) TXT(2) KEY(2) IPSECKEY(2);
            };
    };
    
    $ cat mip6.de.db
    $TTL 5h
    @     IN SOA  ns1 hostmaster  (
                       1       ; Serial
                       86400   ; Refresh
                       1800    ; Retry
                       2W      ; Expire
                       7200 )  ; Minimum
    
           IN  NS  ns1.hznet.de.    // put your name servers here
           IN  NS  ns2.hznet.de.
    
    // add glue records if your ns are within the domain
    //ns1   IN A    192.0.0.2
    //ns1   IN AAAA 2001:db8::53
    
    $ cp mip6.de.db mip6.de.ddb
    $ rndc reconfig
  4. Register the domain, so that the name server is delegated by the parent
    This is part of the domain registration process and depends on your registrar.

  5. Download ddnsupd on the Linux or MAC OS/x client and move it to your bin directory

      $ wget https://www.hznet.de/tools/ddnsupd
      $ mv ddnsupd ~/bin/
  6. Create a SIG0 key on the client.
    Make sure that your hostname is set correct. If not, use option -h whenever you run ddnsupd.

    $ mkdir ~/keys
    $ cd ~/keys
    $ hostname
    host.mip6.de.
    $ ddnsupd createkey
    $ ls -l K*
    -rw-rw-r-- 1 hoz hoz  568 Mai 25 12:29 /home/hoz/keys/Khost.mip6.de.+008+35565.key
    -rw------- 1 hoz hoz 2459 Mai 25 12:29 /home/hoz/keys/Khost.mip6.de.+008+35565.private
  7. Put the KEY record for the dynamic host into the domain

    $ sed -e "s/^/add /" -e '$a send' Khost*.key |          1
    > ssh ns1 nsupdate -k <your-master-hmac-key-file-name>
    
    $ dig +noall +answer KEY host.mip6.de
    host.mip6.de.           7165    IN      KEY     16896 3 8 [key id = 35565] 2
    1 This kind of sed call works with GNU sed(1) only
    2 The key material is suppressed here, because dig runs with option +nocrypto (set within ~/.digrc).
  8. Use ddnsupd to add your current ip address

    $ ddnsupd showall
    mip6.de.                18000 IN SOA ns1.hznet.de. hostmaster.hznet.de. (
                                    1621949136 ; serial
                                    43200      ; refresh (12 hours)
                                    1800       ; retry (30 minutes)
                                    1209600    ; expire (2 weeks)
                                    7200       ; minimum (2 hours)
                                    )
    host.mip6.de.           18000   IN      KEY     16896 3 8 [key id = 35565]
    
    $ ddnsupd add
    
    $ ddnsupd showall
    mip6.de.                18000 IN SOA ns1.hznet.de. hostmaster.hznet.de. (
                                    1621949159 ; serial
                                    43200      ; refresh (12 hours)
                                    1800       ; retry (30 minutes)
                                    1209600    ; expire (2 weeks)
                                    7200       ; minimum (2 hours)
                                    )
    host.mip6.de.           7200    IN      AAAA   2003:2b:d31:5700:b34e:be2f:2c3d:69a2
    host.mip6.de.           18000   IN      KEY    16896 3 8 [key id = 35565]