#!/usr/bin/env perl
# @(#) DtDNS.pl  Update client for www.dtdns.com; performs Dynamic
#                DNS updates as requested. Rev'd: 2014-03-25.
#
# Copyright (c) 2013 Graham Jenkins <grahjenk@cpan.org>. All rights reserved.
# This program is free software; you can redistribute it and/or modify it under
# the same terms as Perl itself.

use strict;
use warnings;
use File::Basename;
use Sys::Syslog;
use LWP::Simple;
use vars qw($VERSION);
$VERSION = "1.04";

# Check usage, open configuration file
my $Minutes;
if ( ($#ARGV == 1) && ($ARGV[0] =~ m/^\d+$/) ) { $Minutes=shift }
if ( $#ARGV != 0 ) {
  die "Usage: ".basename($0)." [repeat-interval] config-file\n".
      " e.g.: ".basename($0)." 30 /usr/local/etc/DtDNS.conf\n"
}
if ( ! open(CF,$ARGV[0]) ) { die "Can't read file: ".$ARGV[0]."\n" }

# Read and store valid records, then close the file
my %Pass;
while (<CF>) {
  chomp;
  if ( length() < 2 ) { next }
  my ($Line)=split;
  my ($h,$p) = split /:/, $Line;
  if ( defined($p) && ($h !~ /\043/) ) { $Pass{$h}=$p }
}
close(CF);
if ( keys(%Pass) < 1 ) { die "No valid records found in file: ".$ARGV[0]."\n" }
  
# Assemble the client name, force an address update on first pass, enter loop
my ($ClNm,$OldAddress,$ChangeTime,$Status)=(basename($0)."-".$VERSION,"",0,-1); 
while (1) {
  # Get current address
  if( defined(my $Address=get("http://myip.dtdns.com")) ) {
    chomp ($Address);
    syslog("info","Vers: $VERSION. Current address is: $Address");
    # Update each host record on first pass or if current address changed
    if ( $Address ne $OldAddress ) {
      foreach my $h ( keys(%Pass) ) { 
        syslog("info","Attempting update for $h");
        my $p=$Pass{$h};
        if( defined(my $Response=get(
          "https://www.dtdns.com/api/autodns.cfm?id=$h&pw=$p&client=$ClNm")) ) {
          syslog("info",$Response);
          if( $Response=~m/now points/ ) {
            $OldAddress=$Address; $ChangeTime=time(); $Status=0
          }
        }
        else { syslog("info","No response from server!") }
      }
    }
  }
  else { syslog("info","Vers: $VERSION. Unable to determine current address!") }
  if ( defined($Minutes) ) {sleep(60*$Minutes)}
  else                     {exit($Status)     }
  # Force an address update on next pass if there hasn't been one for 7 days
  if ( ( time() - $ChangeTime ) > 7*24*3600 ) { $OldAddress="" }
}

__END__

=head1 NAME

DtDNS - update client for www.dtdns.com

=head1 README

DtDNS will update one or more designated DNS records at
www.dtdns.com either once or periodically.

=head1 DESCRIPTION

C<DtDNS> is a simple update client for the DtDNS dynamic
DNS service. It will attempt an immediate update when called,
then optionally loop at designated intervals, attempting 
further updates when necessary.

=head1 USAGE

=over 6

DtDNS [repeat-interval] config-file

=back

e.g.: DtDNS 30 /usr/local/etc/DtDNS.conf

The repeat-interval value (where present) must be
expressed as a positive integer number of minutes.

The config-file value must be the name of a configuration
file which contains one or more hostname:password records
where each password relates to the owner of the
corresponding hostname. Each record should appear on a
separate line thus:

  lassie.dtdns.net:secret1
  fido.etowns.org:secret2
   .. etc.


It is suggested that the configuration file should be
readable only by the intended program-user.

=head1 SCRIPT CATEGORIES

Networking
UNIX/System_administration

=head1 AUTHOR

Graham Jenkins <grahjenk@cpan.org>

=head1 COPYRIGHT

Copyright (c) 2013 Graham Jenkins. All rights reserved.
This program is free software; you can redistribute it
and/or modify it under the same terms as Perl itself.

=cut
