Cover V13, i09

Article

sep2004.tar

DNS Security Protocols I: Dynamic Updates

Kerry Thompson

Of all of the many network protocols used in computer networking, DNS is one of the most fundamental and important. The task of mapping domain names to IP addresses seems simple, and at first approach it is. However, issues arise when that protocol becomes extensively trusted by systems. Packets within the DNS protocol are all sent as clear text, which means that they can easily be read and modified while in transit. DNS uses the UDP protocol, which has no handshaking between clients and servers and is therefore quite susceptible to spoofing attacks. We no longer have a trusted Internet in which we can trust insecure services -- there are malicious attackers that will do their very best to make users go to spoofed banking sites, to swamp everyone with spam, and to generally wreak havoc.

This article is the first of two in which I will be looking at the use of cryptographic methods to secure DNS. In this article, I will cover secure dynamic updates and zone transfers using TSIG keys; in the second article, I will cover the DNSSEC protocols for securing zone data.

In my examples, I'm using an installed copy of ISC BIND version 9.3.0rc2 from www.isc.org, which has been set up to serve a test domain "domain.tld" and a reverse domain "1.168.192.in-addr.arpa".

I won't cover the installation of the BIND software here, but it is quite straightforward. Note that you will need to add the "--with-openssl" option to the ./configure command if you want to use the DNSSEC functionality.

Secure Dynamic Updates

Using dynamic updates is a great way to maintain your DNS zone data. With some knowledge and a bit of practice, you will probably find this method easier and less mistake-prone than the old-fashioned way of editing zone files (don't forget to update that serial number!). Enabling dynamic updates is easy, but care must be taken to make sure the setup is secure. Although you can restrict updates by their originating IP address, this approach is not very secure because updates use UDP, which is quite easily spoofed. A better method is to sign the updates with Transaction Signature (TSIG) keys and permit only updates with authorized keys.

Keys are simply base-64 encoded random data that is shared by the DNS server and the client system sending updates. To generate a key for updates, use the dnssec-keygen command:

dnssec-keygen -a HMAC-MD5 -b 512 -n HOST update_key
This generates a 512-bit key with the HMAC-MD5 algorithm and places the result into two files: Kupdate_key.+157+59571.key and Kupdate_key.+157+59571.private for the public and private key data. The numbers in the key file name are for the key algorithm (157 for HMAC-MD5) and a 5-digit random key identifier (which will be different on your system). Store both key files in /var/named or wherever you keep DNS zone files on your DNS server. Next, configure your DNS server to accept updates signed with this key, edit /etc/named.conf, and add the definition for the key:

key update_key {
    algorithm HMAC-MD5;
    secret "fxT7q+Kq8TUmZrN4edxAVeTeOmiX/3A6HQ40HcyI...g==";
};
where the secret string is extracted from the private key file (it has been truncated in this example). You won't be able to include the key file directly into the named.conf file (with the "include" statement) because the key files generated by dnssec-keygen are formatted to be included into zone files and the syntax is different to what the configuration file uses. Then, edit /etc/named.conf and configure a zone to receive updates with this key, edit your zone definition, and add an allow-update option:

zone "domain.tld" IN {
    type master;
    file "domain.tld";
    allow-update { key update_key; };
};
Don't forget the reverse zone as well:

zone "1.168.192.in-addr.arpa" IN {
    type master;
    file "1.168.192.in-addr.arpa";
    allow-update { key update_key; };
};
You can add a finer level of control with the update-policy option, for example:

zone "1.168.192.in-addr.arpa" IN {
    type master;
    file "1.168.192.in-addr.arpa";
    update-policy { grant update_key name * A; };
};
This would grant changes to A (Address) records only for requests signed with the update_key key.

Now, restart your DNS server, check the syslog for any errors, and test the updates from the command line:

/usr/local/bin/nsupdate -k Kupdate_key.+157+59751.key <<END
  ; set the server explicitly
  server 192.168.1.3
  ; create a test update
  update add testrec.domain.tld 86400 IN A 192.168.1.10
  show
  send
END
This example sends a single update to add an A record into the domain.tld zone. You can use either "nslookup", "dig", or the "host" commands to check that the update has been made. The DNS server will also log an entry in syslog recording the update.

Naturally, I like to use Perl to get the job done efficiently. Using the Net::DNS package, you can use Perl to perform updates:

#!/usr/bin/perl -w
use Net::DNS;
use strict;

my $key_name = 'update_key';
my $key = 'fxT7q+Kq8TUmZrN4edxAVeTeOmiX/3A6HQ40HcyI...g==';

# Create the update packet.
my $update = Net::DNS::Update->new('domain.tld');

# Add a TXT record to the domain
$update->push(update => rr_add('testrec.domain.tld 86400 IN TXT \
  "A test record"'));

# Send the update to the zone's primary master.
my $res = Net::DNS::Resolver->new;
$res->nameservers('192.168.1.3');

# Sign the update message
$update->sign_tsig($key_name, $key);

my $reply = $res->send($update);

# Check return code
if ($reply) {
  if ($reply->header->rcode eq 'NOERROR' ) {
    print "Update succeeded\n";
  } else {
    print 'Update failed ', $reply->header->rcode, "\n";
  }
} else {
  print 'Update failed', $res->errorstring, "\n";
}
This example creates a new TXT record called "testrec.domain.tld". Note that you can make multiple updates within a single request packet -- they can even include multiple add and delete operations, but only if they are all under the same domain. Also note that dynamic updates simply increment the zone serial number in the SOA record, it doesn't maintain the YYYYMMDD sort of format often used for serial numbers.

Note that once you start using dynamic updates, you can't really use manual editing of the zones anymore. The BIND server maintains journal files that contain a record of dynamic updates, and these must be taken into account. If you do need to edit a zone manually, you must shut down the DNS server, remove the zone journal (.jnl) file, edit the zone, and restart the server.

TSIG-Secured Zone Transfers

It's also very useful to secure the transfers of zone data between master and slave DNS servers. This is particularly relevant if the transfers are taking place across untrusted networks such as the public Internet. As mentioned before, the data being transferred is all in plain-text and contains no checking mechanism, so there is a risk of data corruption or malicious interference of the data being transferred. We can easily use TSIG keys to sign the zone transfer data.

To begin, generate a key to be used for zone transfers. This should not be the same as the key you created for dynamic updates. You could create a separate key for each slave server, but in the examples that follow I've created a single key for all slaves.

Generate a new key on the master, named "slave_xfers_key":

dnssec-keygen -r /dev/urandom -a HMAC-MD5 -b 128 -n HOST slave_xfers_key

Copy the key data string from the created key file into /etc/named.conf on the master server:

key slave_xfers_key {
      algorithm HMAC-MD5;
      secret "mv0NxiVT4ho/TZbvPID+Kg==";
};
Then, permit zone transfers on the master server for clients with the key by adding allow-transfer statements in /etc/named.conf:

zone "domain.tld" IN {
      type master;
      file "domain.tld";
      allow-update { key update_key; };
      allow-transfer { key slave_xfers_key; };
};

zone "1.168.192.in-addr.arpa" IN {
      type master;
      file "1.168.192.in-addr.arpa";
      allow-update { key update_key; };
      allow-transfer { key slave_xfers_key; };
};
Restart the master server and make sure there are no errors in the syslog (it is quite easy to forget those semicolons in named.conf files).

On the slave server, configure the same key for the zone in /etc/named.conf:

key slave_xfers_key {
      algorithm HMAC-MD5;
      secret "mv0NxiVT4ho/TZbvPID+Kg==";
};
Then, add a "server" statement specifying the TSIG key that this slave will use when communicating to the specified server:

server 192.168.1.3 {
  keys { slave_xfers_key; };
};
The definitions for the slave zones stay the same; there is no need to configure the key in them. The slave server will automatically use the TSIG key when requesting a transfer of any zone from the master server whose IP address was specified in the server statement.

Now, restart the slave server and check syslog for errors. If the TSIG-secured zone transfer was successful, you should see the following syslog messages on the slave server:

named[3733]: zone domain.tld/IN: Transfer started.
named[3733]: transfer of 'domain.tld/IN' from 192.168.1.3#53: \
  connected using 192.168.1.2#32835
named[3733]: zone domain.tld/IN: transferred serial 1: \
  TSIG 'slave_xfers_key'
named[3733]: transfer of 'domain.tld/IN' from 192.168.1.3#53: \
  end of transfer
and similar messages on the master server describing the transfer of the zone using the slave_xfers_key TSIG key.

DHCP Dynamic Updates

DHCP servers can also send dynamic updates to DNS servers as they allocate IP addresses to clients, and naturally you will want to secure these updates with TSIG signatures. This is relatively easy to configure when using ISC's DHCPD server as follows.

In this scenario, you have a client device (such as a laptop) that wants to connect to networks and be allocated an IP address (otherwise known as a DHCP lease). The client would also like to choose its own host name on the network to be inserted into DNS. In this example, I'll configure my Linux-based laptop to have the name "gorgon" allocated to it when it connects to networks with a DHCP server and dynamic DNS updates that permit client-elected names.

There are three steps necessary to achieve this, which I will explain below:

1. Configure the DHCP server and DNS server to use TSIG dynamic updates.

2. Configure the DHCP server to update the DNS server each time a lease is let for the subnet.

3. Configure the DHCP client to give the DHCP server a domain name to insert into DNS.

Step 1. I've already configured the DNS server to permit signed updates above. So, using the ISC DHCPD server, you can configure the update_key by adding the following into /etc/dhcpd.conf:

key update_key {
  algorithm HMAC-MD5;
  secret "fxT7q+Kq8TUmZrN4edxAVeTeOmiX/3A6HQ40HcyI...g==";
}

zone 1.168.192.in-addr.arpa {
  key update_key;
  primary 192.168.1.3;
}

zone domain.tld {
  key update_key;
  primary 192.168.1.3;
}

ddns-updates on;
ddns-update-style interim;
allow client-updates;
Step 2. When the DHCP server leases an address for a subnet, instruct it to also send a DNS update; in /etc/dhcpd.conf, add a couple of lines to the subnet statement:

subnet 192.168.1.0 netmask 255.255.255.0 {
    option domain-name "domain.tld";
    option domain-name-servers 192.168.1.3;
    option routers 192.168.1.1;
    range 192.168.1.20 192.168.1.254;

    # Dynamic DNS updates:
    ddns-domainname "domain.tld";
    ddns-rev-domainname "1.168.192.in-addr.arpa";
}
Step 3. Configure the DHCP-enabled clients to send their names to the DHCP server. Most Windows clients seem to do this automatically, but some *nix DHCP clients need configuration. If you are using the ISC DHCP client software, this is in /etc/dhclient.conf and should look like the following example:

   send host-name "gorgon";
   send fqdn.fqdn "gorgon.domain.tld.";
   send fqdn.encoded on;
   send fqdn.server-update on;
Once the DHCP server has been restarted, and the client requests a DHCP lease, the server should send a TSIG-signed dynamic DNS update to the master DNS server to add the name of the client as an A record, and the reverse PTR record.

There are a number of ways to integrate DHCP and dynamic DNS. An alternative to the above could be to have the clients call a script after they get a DHCP lease and use nsupdate to send the updates themselves. In this case, each client would need a TSIG key in order to secure the update packets.

Conclusion

In this article, I've shown how to set up and use TSIG-signed DNS updates, TSIG-secured zone transfers, and TSIG-secured dynamic updates from a DHCP server. Next month, I will look at DNSSEC-secured zones in which the actual zone resource records are signed with cryptographic keys. This method is used to ensure that the queries from a DNS client are valid and come from the true server for the domain.

References

Secure Dynamic DNS HOWTO -- http://ops.ietf.org/dns/dynupd/secure-ddns-howto.html

Dynamic DNS updates with isc-dhcpd -- http://tinyurl.com/6lssd

BIND v9 ARM (Administrators Reference Manual) -- http://www.nominum.com/content/documents/bind9arm.pdf

DNSSEC Operations HOWTO -- http://www.ripe.net/disi/Course/TechCourse.pdf

Kerry Thompson is a CISSP-certified security consultant for Open Systems Specialists in Auckland, New Zealand. He has been working in Unix systems administration and security for many years and regularly writes articles on IT security. Contact him at kerry@crypt.gen.nz.