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.
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 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.