6. Updating the nameserver information

Script on the server
The script on the client

The interesting part is making the updates happen. There are two parts to this, the script to be run on the server and the call to that script on the client side.

Script on the server

This is a Perl script which is an adaptation of the script from Use Dynamic DNS for fun and profit!. I modified it slightly to allow me to update the zone top.

#!/usr/bin/perl -w

use strict;
use Net::DNS;
use vars qw ($zone $name $rr $res $query $update $ans $b);

if ($ARGV[0]){
        $zone="cable.example.com";
        $name="cable.example.com";
        $res = new Net::DNS::Resolver;
        $res->nameservers("127.0.0.1");
        $query = $res->search($name);
        if ($query){
                print "Attempting to remove old entry: $name = ";
                foreach $rr ($query->answer) {
                        next unless $rr->type eq "A";
                        print $rr->address, " ";
                }
                print "\n";
                $update = new Net::DNS::Update($zone);
                # Prerequisite (assumed) is that an A record must already exist.
                $update->push("update",
                        $b = new Net::DNS::RR(Name    => $name,
                                Type => "A",
                                Ttl => 0,
                                Class => "ANY",
                                Rdata => ""));
                $res = new Net::DNS::Resolver;
                $res->nameservers("127.0.0.1");
                $ans = $res->send($update);
                if (defined $ans) {
                        print "Return code: ", $ans->header->rcode, "\n";
                        if ($ans->header->rcode eq "NOERROR") {
                                print "Old entry removed successfully.\n";
                        } else {
                                print "Failed to remove old data!!!\n";
                        }
                } else {
                        printf("Error: %s\n",$res->errorstring);
                        print "Failed to remove old data!!!!\n";
                }
        }
        $update = new Net::DNS::Update($zone);
        # NXRRSET - Prerequisite is that no A records exist for the name.
        $update->push("pre", new Net::DNS::RR(Name  => $name,
            Class => "NONE",
            Type  => "A"));
        # Add one A records for the name.
        $update->push("update", new Net::DNS::RR(Name    => $name, 
            Ttl     => 1800, 
            Type    => "A",
            Address => $ARGV[0]));
        $res = new Net::DNS::Resolver;
        $res->nameservers("127.0.0.1");
        $ans = $res->send($update);

        if (defined $ans) {
                print "Return code: ", $ans->header->rcode, "\n";
                if ($ans->header->rcode eq "NOERROR") {
                        print "Success!\n";
                } else {
                        print "Failure!\n";
                }
        } else {
                printf("Error: %s\n",$res->errorstring);
                print "Failure!\n";
        }
}

This script simply tries to remove the current A record for cable.example.com (which is why the zone needed to be preloaded with an IP) and then loads the new one that was given as argument.

The script on the client

The client (my system connected to the cablemodem) needs to do the call at the right moment. The right moment being when the PPP connection is up and has an ip number assigned. This is easy since pppd has the option of running the ip-up script when the ip number is assigned. In Debian Linux there is a /etc/ppp/ip-up.d/ directory for scripts to be executed. I added a dyndns script to the directory with:

#!/bin/sh

ssh -P dyndns@ns1.example.com "bin/updatedns $PPP_LOCAL"

The interesting part is that this has to happen as a passwordless action, so root on the ppp machine has a generated ssh public key which is in the authorized_keys of the dyndns account.


Koos van den Hout (koos@kzdoos.xs4all.nl)