Update DNS with nsupdate

De Wiki do Bernardino
Ir para: navegação, pesquisa

Install with authentication

Install nsupdate by installing bind9 on your dhcp client. Run dnssec-keygen as follows to create a key pair for authenticating updates.

dnssec-keygen -a HMAC-MD5 -b 128 -n HOST www.foo.ca.

Yes, include that dot at the end, to be fully qualified (good habit). Remember,everything depends on that name. It will look like this:


I have seen a machine or two be fussy about this being run at the console only. This produces two files with names starting with K, with numbers and "+"s at the end, as above. Put these keys into /var/named with 600 permissions, and sftp them to your ns,putting the keys into its /var/named; confirm 600 permissions (should be fine). You will need an include statement in your name server's named.conf file, which will point at a conf file referencing your key.

Call it dnskeys.conf, creating it in /var/named as such:

key  www.foo.ca. {       
       algorithm hmac-md5;

secret "adsfjiott9054kfahG5+Zg=="; };

This file must reference the exact keyname you created with dnssec-keygen. It does not work otherwise. This means everything after the "K" but before the "+157" stuff. Has to be. The secret key is, well, the key in that file.

This file must be in /var/named, and be pointed to in named.conf as follows:

/* Global options */
include "dnskeys.conf";

options {
       /* BIND directory */
       directory "/var/named";
       version " " ;

zone "foo.ca" in {
       type master;
       file "db.foo.ca";
       allow-transfer {; };
       allow-update { key www.foo.ca.; };

/var/named is pointed at the dnskeys.conf file, and is specifically toldto only allow updates to www.foo.ca. from a host presenting the correct key.

Restarting your named should result in no errors to /var/log/messages. Test updating from www.foo.ca. with an update command.

/usr/local/bin/nsupdate -k /var/named/Kwww.foo.ca.+157+34827.key -d /etc/nsupdate

I use a shell script to refresh my IP on dhcp clients.

IPADDR=`/sbin/ifconfig ep0|grep 'inet [0-9]'|tr -s " "|cut -d" " -f2`
echo "update delete www.foo.ca. A" > /etc/nsupdate
echo "update add www.foo.ca. 21600  IN A $IPADDR" >> /etc/nsupdate
echo "" >> /etc/nsupdate
/usr/local/bin/nsupdate -k /var/named/Kwww.foo.ca.+157+34827.key -d /etc/nsupdate

It is critical that /etc/nsupdate has that blank line in it! The script carves out our current IP from ifconfig, populating a variable, which is written into /etc/nsupdate, which in turn is then called as an argument to nsupdate to do the job. Make sure the script runs without error. Check to make sure that the timeout value (21600 in the above example) is sane. If it is too low, meaning lower than your named.conf refresh time, you will get "non-existent zone" errors for your perfectly functional zone if the client's lease is held for a longer time. Unexpected, but possible.

See below for how I am running this script in cron to maintain accurate dns.

It is also critical that /etc/resolv.conf contains the right information. You must configure /etc/dhclient.conf so that your nameserver and domain are not overwritten by the dhcp server's offer. Mine looks like this:

Update as of Jan 23, 2004: A correct supersede line in /etc/dhclient.conf looks like this below. Your list of name servers must be comma separated. You also want the first one listed to be the one receiving the update from the dhcp client. If this sounds obvious, it's not. You may send nsupdate requests as frequently as your cronjob says to lookup only nameservers. With the right nameserver listed first in the supersede statement, you hitthe right machine first.

      interface "ep0" {
          supersede domain-name "foo.ca";
          supersede domain-name-servers,,;
          request subnet-mask, broadcast-address, time-offset, routers,
                domain-name-servers, host-name;
          require subnet-mask;

      alias {
        interface "ep0";
        option subnet-mask;

This means that the dhcp info does not stomp on resolv.conf; nsupdate reads resolv.conf to find out to whom it should send the update. I also configure an internal alias on my nic, so I don't need two nics. This does not work with samba for some reason; it just doesn't.

The shell script above needs to be called by dhclient whenever it runs and also in a cron job. Make sure the script contains absolute paths (good habit) to everything. It needs to exist as dhclient_exit_hooks in /etc and be executable (which it probably already is, if you have been following along).

Test it with:

/etc/rc.d/dhclient restart > dhclient.log 2>&1

and ensure that the update succeeded on dhclient exit.

I have found that you need to have fairly frequent updates to keep your records fresh, and I am using a cron call to /etc/dhclient-exit-hooks, running it every 15 minutes. I have several domains doing simultaneous updates. The last four lines of the script is just repeated with the domain name tacked onto the end of the /etc/nsupdate file which is created, so that /etc/nsupdate_foo is created, and used as the input to the actual nsupdate run in dhclient_exit_hooks by cron.

Change a dynamic Zone ("allow-update")

To make any changes to zones to which you are allowing nsupdate you will need to comment out the "allow-update" lines in named.conf, restart named before you make the change, this remove any .jnl files, make changes increment the serial on the zonei, activate again "allow-update" line and restart named. Key based updating prevents any manual updates from registering with named. Commenting out the updating allows the manual update to happen (confirmed by AXFRs) from slaves; once the manual change has pushed out, you can uncomment the nsupdate allow lines in named.conf for the zone and let nsupdate do its work again.

BIND with Microsoft

Most of this works fine with BIND nsupdate on Windows2000. You need to set the pretend /etc/resolv.conf located in c:\winnt\system32\drivers\etc\resolv.conf to contain a line for the nameserver receiving updates for the zone. nameserver The syntax is a little different but it works.

Here is a tested procedure for updating WinXP to Bind9 unix.

The valid syntax for Windows nsupdate is as follows:

C:\bind\bin>nsupdate -k c:\Kcsait.ca.+157+nnnnn.key -d c:\update.txt
Creating key...

The network time has to be synchronized between WinXP and the name server, or the update fails. This is done in "Date and Time Properies/Internet Time" on Control Panel.

This script "getip.cmd" pulls ip address and hostname from WindowsXP and creates the update file for nsupdate to use.

@echo off
:: Get the IP address

for /f "tokens=2-6 delims=:. " %%a in ('ipconfig') do if "%%a"=="Address" (if not "%%b"=="0" call :test %%b %%c %%d %%e)
goto :EOF

    if %1==10 goto nsupdate
    goto :EOF


echo update delete %USERDOMAIN%.csait.ca. A > c:\update.txt
echo update add %USERDOMAIN%.csait.ca. 86400 IN A %1.%2.%3.%4 >> c:\update.txt

c:\bind\bin\nsupdate -k c:\Kcsait.ca.+157+56788.key -d c:\update.txt   


As long as the path to your nsupdate.exe is valid, your update will send to the name server listed in your c:\windows\system32\drivers\etc\resolv.conf.

Simple Updates

Update machine address in DNS and respective reverse, with command line:

> update add machine1.test.pt 86400  A             
> send 
> update add 86400 PTR machine1.test.pt.
> send

In a script

  echo "update add machine1.test.pt 86400  A"
  echo "update add 86400 PTR machine1.test.pt."
} | nsupdate -v -d