# HG changeset patch # User Heiko Schlittermann (JUMPER) # Date 1400794463 -7200 # Node ID 286a373ab86b7c62b732dbee16be7047c9391204 # Parent 271dfe27e1d336ab6f3a894d8792611a5cdbe13c renamed to DNS::Vi diff -r 271dfe27e1d3 -r 286a373ab86b Build.PL --- a/Build.PL Thu May 22 23:31:14 2014 +0200 +++ b/Build.PL Thu May 22 23:34:23 2014 +0200 @@ -1,10 +1,10 @@ use Module::Build; Module::Build->new( - dist_name => 'vidns', - dist_version_from => 'bin/vidns', + dist_name => 'dnsvi', + dist_version_from => 'bin/dnsvi', dist_abstract => 'simple script to edit dynamic DNS zones', - script_files => ['bin/vidns'], + script_files => ['bin/dnsvi'], requires => { perl => 5.010, } diff -r 271dfe27e1d3 -r 286a373ab86b bin/dnsvi --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/dnsvi Thu May 22 23:34:23 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 DNS::Vi; + +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 271dfe27e1d3 -r 286a373ab86b bin/vidns --- a/bin/vidns Thu May 22 23:31:14 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -#! /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 271dfe27e1d3 -r 286a373ab86b lib/DNS/Vi.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/DNS/Vi.pm Thu May 22 23:34:23 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{^(?