# HG changeset patch # User Heiko Schlittermann (JUMPER) # Date 1400794274 -7200 # Node ID 271dfe27e1d336ab6f3a894d8792611a5cdbe13c # Parent 70ecc18829685ba3a02333e186cc0e0ebd4af1f2 seems to work so far needs to be done: -l for local auth diff -r 70ecc1882968 -r 271dfe27e1d3 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Thu May 22 23:31:14 2014 +0200 @@ -0,0 +1,4 @@ +syntax:glob +_build/ +blib/ +Build diff -r 70ecc1882968 -r 271dfe27e1d3 Build.PL --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Build.PL Thu May 22 23:31:14 2014 +0200 @@ -0,0 +1,11 @@ +use Module::Build; + +Module::Build->new( + dist_name => 'vidns', + dist_version_from => 'bin/vidns', + dist_abstract => 'simple script to edit dynamic DNS zones', + script_files => ['bin/vidns'], + requires => { + perl => 5.010, + } +)->create_build_script; diff -r 70ecc1882968 -r 271dfe27e1d3 bin/vidns --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/vidns Thu May 22 23:31:14 2014 +0200 @@ -0,0 +1,100 @@ +#! /usr/bin/perl +#line 2 +use 5.010; +use strict; +use warnings; +use if $ENV{DEBUG}//'' eq 'vidns' => 'Smart::Comments'; +use File::Temp; +use Getopt::Long; +use Pod::Usage; + +use blib; +use ViDNS; + +sub main { + my %o = ( + key => undef, + server => undef, + debug => undef, + ); + + GetOptions( + 'k|key=s' => \$o{key}, + 's|server=s' => \$o{server}, + 'd|debug!' => \$o{debug}, + ) + && @ARGV == 1 + or pod2usage(); + + my @dig = ( + dig => 'AXFR', + defined $o{key} ? (-k => $o{key}) : (), + defined $o{server} ? ("\@$o{server}") : (), + $ARGV[0] + ); + + my @zone1 = grep { + not $_->{rrset}{rrtype} ~~ + [qw(RRSIG NSEC3 NSEC3PARAM NSEC DNSKEY TSIG)] + } parse($_ = `@dig`) or die $_; + + my $tmp = File::Temp->new(); + $tmp->print(nice @zone1); + $tmp->flush(); + system $ENV{EDITOR} // 'vi' => $tmp->filename; + $tmp->seek(0, 0); + my @zone2 = parse(<$tmp>); + my ($add, $del) = delta(\@zone1, \@zone2); + + my @cmds = ((map { "update add $_" } @$add), + (map { "update delete $_" } @$del)); + + print <<_EOF, join "\n" => @cmds, ''; +# The following commands are about to be sent via nsupdate +# to the master server: +_EOF +print '# Please confirm (yes/no): '; +return 1 if ne "yes\n"; + + my @nsupdate = ('nsupdate', defined $o{debug} ? ('-d') : (), defined $o{key} ? (-k => $o{key}) : ()); + open(my $nsupdate, '|-') or do { + exec @nsupdate; + die "Can't exec @nsupdate: $!\n"; + }; + print $nsupdate join "\n", @cmds, 'send', ''; + close($nsupdate); + say "nsupdate returned $?"; + return 0; +} + +exit main(@ARGV) if not caller; + +__END__ + +=head1 NAME + + vidns -- editor for dynamically maintained zones + +=head1 SYNOPSIS + + vidns [-k key] [-s server] [-d] + +=head1 DESCRIPTION + +=head1 PREREQUISITES + +We need some tools to be installed: + +=over + +=item B + +The domain information grabber is used for the zone transfer currently. + +=item B + +The nsupdate tool is used to send the updates back to the server. + +=back + +=cut diff -r 70ecc1882968 -r 271dfe27e1d3 lib/ViDNS.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/ViDNS.pm Thu May 22 23:31:14 2014 +0200 @@ -0,0 +1,175 @@ +use 5.010; +use strict; +use warnings; +use if $ENV{DEBUG}//'' eq 'vidns' => 'Smart::Comments'; +use Digest::SHA qw(sha512_hex); + +use base 'Exporter'; + +our @EXPORT = qw(ttl2h h2ttl parse delta); +our @EXPORT_OK = (); + +sub parse { + my $data = join '', @_; + my @lines = split /\n/, $data; + + my @zone; + my ($origin, $ttl, $last_label, $soa_seen); + + foreach (@lines) { + s{;.*$}{}; + given ($_) { + when (m{^\s*$}) { next } + when (m{^\s*\$ORIGIN\s+(\S+)}) { $origin = $1 } + when (m{^\s*\$TTL\s+(\S+)}) { $ttl = $1 } + when ( + m{^(?